Merge pull request #8 from AnonymusRaccoon/repositories

Repositories
This commit is contained in:
Zoe Roux 2020-06-07 20:01:58 +02:00
commit 6ecc031c94
56 changed files with 2026 additions and 801 deletions

View File

@ -1,58 +1,93 @@
using Kyoo.Models; using System.Collections.Generic;
using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using JetBrains.Annotations;
using Kyoo.Models;
namespace Kyoo.Controllers namespace Kyoo.Controllers
{ {
public interface ILibraryManager public interface ILibraryManager
{ {
// Get by slug // Get by slug
Library GetLibrary(string librarySlug); Task<Library> GetLibrary(string slug);
Collection GetCollection(string slug); Task<Collection> GetCollection(string slug);
Show GetShow(string slug); Task<Show> GetShow(string slug);
Season GetSeason(string showSlug, long seasonNumber); Task<Season> GetSeason(string showSlug, int seasonNumber);
Episode GetEpisode(string showSlug, long seasonNumber, long episodeNumber); Task<Episode> GetEpisode(string showSlug, int seasonNumber, int episodeNumber);
Episode GetMovieEpisode(string movieSlug); Task<Episode> GetMovieEpisode(string movieSlug);
Genre GetGenre(string slug); Task<Track> GetTrack(int id);
Studio GetStudio(string slug); Task<Track> GetTrack(int episodeID, string language, bool isForced);
People GetPeople(string slug); Task<Genre> GetGenre(string slug);
ProviderID GetProvider(string name); 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 // Get all
IEnumerable<Library> GetLibraries(); Task<ICollection<Library>> GetLibraries();
IEnumerable<Collection> GetCollections(); Task<ICollection<Collection>> GetCollections();
IEnumerable<Show> GetShows(); Task<ICollection<Show>> GetShows();
IEnumerable<Episode> GetEpisodes(); Task<ICollection<Season>> GetSeasons();
IEnumerable<Track> GetTracks(); Task<ICollection<Episode>> GetEpisodes();
IEnumerable<Studio> GetStudios(); Task<ICollection<Track>> GetTracks();
IEnumerable<People> GetPeoples(); Task<ICollection<Studio>> GetStudios();
IEnumerable<Genre> GetGenres(); Task<ICollection<People>> GetPeoples();
Task<ICollection<Genre>> GetGenres();
Task<ICollection<ProviderID>> GetProviders();
// Search // Search
IEnumerable<Collection> SearchCollections(string searchQuery); Task<ICollection<Library>> SearchLibraries(string searchQuery);
IEnumerable<Show> SearchShows(string searchQuery); Task<ICollection<Collection>> SearchCollections(string searchQuery);
IEnumerable<Episode> SearchEpisodes(string searchQuery); Task<ICollection<Show>> SearchShows(string searchQuery);
IEnumerable<Genre> SearchGenres(string searchQuery); Task<ICollection<Season>> SearchSeasons(string searchQuery);
IEnumerable<Studio> SearchStudios(string searchQuery); Task<ICollection<Episode>> SearchEpisodes(string searchQuery);
IEnumerable<People> SearchPeople(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 //Register values
void Register(object obj); Task RegisterLibrary(Library library);
Task Edit(object obj, bool resetOld); Task RegisterCollection(Collection collection);
void RegisterShowLinks(Library library, Collection collection, Show show); Task RegisterShow(Show show);
Task SaveChanges(); 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 // Edit values
IEnumerable<MetadataID> Validate(IEnumerable<MetadataID> id); 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 // Delete values
void RemoveShow(Show show); Task DelteLibrary(Library library);
void RemoveSeason(Season season); Task DeleteCollection(Collection collection);
void RemoveEpisode(Episode episode); 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);
} }
} }

View File

@ -14,8 +14,8 @@ namespace Kyoo.Controllers
Task<IEnumerable<Show>> SearchShows(string showName, bool isMovie); Task<IEnumerable<Show>> SearchShows(string showName, bool isMovie);
Task<IEnumerable<PeopleLink>> GetPeople(Show show); 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);
} }
} }

View File

@ -10,8 +10,8 @@ namespace Kyoo.Controllers
Task<Show> CompleteShow(Show show, Library library); Task<Show> CompleteShow(Show show, Library library);
Task<Show> SearchShow(string showName, bool isMovie, Library library); Task<Show> SearchShow(string showName, bool isMovie, Library library);
Task<IEnumerable<Show>> SearchShows(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<Season> GetSeason(Show show, int seasonNumber, Library library);
Task<Episode> GetEpisode(Show show, string episodePath, long seasonNumber, long episodeNumber, long absoluteNumber, 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); Task<IEnumerable<PeopleLink>> GetPeople(Show show, Library library);
} }
} }

View 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> {}
}

View File

@ -11,7 +11,7 @@
<Company>SDG</Company> <Company>SDG</Company>
<PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression> <PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance> <PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<PackageVersion>1.0.20</PackageVersion> <PackageVersion>1.0.21</PackageVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View File

@ -7,7 +7,7 @@ namespace Kyoo.Models
{ {
public class Collection public class Collection
{ {
[JsonIgnore] public long ID { get; set; } [JsonIgnore] public int ID { get; set; }
public string Slug { get; set; } public string Slug { get; set; }
public string Name { get; set; } public string Name { get; set; }
public string Poster { get; set; } public string Poster { get; set; }

View File

@ -2,10 +2,10 @@ namespace Kyoo.Models
{ {
public class CollectionLink public class CollectionLink
{ {
public long ID { get; set; } public int ID { get; set; }
public long? CollectionID { get; set; } public int? CollectionID { get; set; }
public virtual Collection Collection { 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 virtual Show Show { get; set; }
public CollectionLink() { } public CollectionLink() { }

View File

@ -6,21 +6,21 @@ namespace Kyoo.Models
{ {
public class Episode public class Episode
{ {
[JsonIgnore] public long ID { get; set; } [JsonIgnore] public int ID { get; set; }
[JsonIgnore] public long ShowID { get; set; } [JsonIgnore] public int ShowID { get; set; }
[JsonIgnore] public virtual Show Show { 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; } [JsonIgnore] public virtual Season Season { get; set; }
public long SeasonNumber { get; set; } public int SeasonNumber { get; set; }
public long EpisodeNumber { get; set; } public int EpisodeNumber { get; set; }
public long AbsoluteNumber { get; set; } public int AbsoluteNumber { get; set; }
[JsonIgnore] public string Path { get; set; } [JsonIgnore] public string Path { get; set; }
public string Title { get; set; } public string Title { get; set; }
public string Overview { get; set; } public string Overview { get; set; }
public DateTime? ReleaseDate { 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; } [JsonIgnore] public string ImgPrimary { get; set; }
public virtual IEnumerable<MetadataID> ExternalIDs { get; set; } public virtual IEnumerable<MetadataID> ExternalIDs { get; set; }
@ -42,13 +42,13 @@ namespace Kyoo.Models
public Episode() { } public Episode() { }
public Episode(long seasonNumber, public Episode(int seasonNumber,
long episodeNumber, int episodeNumber,
long absoluteNumber, int absoluteNumber,
string title, string title,
string overview, string overview,
DateTime? releaseDate, DateTime? releaseDate,
long runtime, int runtime,
string imgPrimary, string imgPrimary,
IEnumerable<MetadataID> externalIDs) IEnumerable<MetadataID> externalIDs)
{ {
@ -63,16 +63,16 @@ namespace Kyoo.Models
ExternalIDs = externalIDs; ExternalIDs = externalIDs;
} }
public Episode(long showID, public Episode(int showID,
long seasonID, int seasonID,
long seasonNumber, int seasonNumber,
long episodeNumber, int episodeNumber,
long absoluteNumber, int absoluteNumber,
string path, string path,
string title, string title,
string overview, string overview,
DateTime? releaseDate, DateTime? releaseDate,
long runtime, int runtime,
string imgPrimary, string imgPrimary,
IEnumerable<MetadataID> externalIDs) IEnumerable<MetadataID> externalIDs)
{ {
@ -90,7 +90,7 @@ namespace Kyoo.Models
ExternalIDs = externalIDs; 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; return showSlug + "-s" + seasonNumber + "e" + episodeNumber;
} }

View File

@ -4,7 +4,7 @@ namespace Kyoo.Models
{ {
public class Genre public class Genre
{ {
[JsonIgnore] public long ID { get; set; } [JsonIgnore] public int ID { get; set; }
public string Slug { get; set; } public string Slug { get; set; }
public string Name { get; set; } public string Name { get; set; }
@ -24,7 +24,7 @@ namespace Kyoo.Models
Name = name; Name = name;
} }
public Genre(long id, string slug, string name) public Genre(int id, string slug, string name)
{ {
ID = id; ID = id;
Slug = slug; Slug = slug;

View File

@ -2,9 +2,9 @@ namespace Kyoo.Models
{ {
public class GenreLink public class GenreLink
{ {
public long ShowID { get; set; } public int ShowID { get; set; }
public virtual Show Show { 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 virtual Genre Genre { get; set; }
public GenreLink() {} public GenreLink() {}

View File

@ -1,5 +1,4 @@
using System.Collections; using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using Kyoo.Models.Attributes; using Kyoo.Models.Attributes;
using Newtonsoft.Json; using Newtonsoft.Json;
@ -8,7 +7,7 @@ namespace Kyoo.Models
{ {
public class Library public class Library
{ {
[JsonIgnore] public long ID { get; set; } [JsonIgnore] public int ID { get; set; }
public string Slug { get; set; } public string Slug { get; set; }
public string Name { get; set; } public string Name { get; set; }
public IEnumerable<string> Paths { get; set; } public IEnumerable<string> Paths { get; set; }

View File

@ -2,12 +2,12 @@ namespace Kyoo.Models
{ {
public class LibraryLink public class LibraryLink
{ {
public long ID { get; set; } public int ID { get; set; }
public long LibraryID { get; set; } public int LibraryID { get; set; }
public virtual Library Library { 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 virtual Show Show { get; set; }
public long? CollectionID { get; set; } public int? CollectionID { get; set; }
public virtual Collection Collection { get; set; } public virtual Collection Collection { get; set; }
public LibraryLink() { } public LibraryLink() { }

View File

@ -4,20 +4,20 @@ namespace Kyoo.Models
{ {
public class MetadataID public class MetadataID
{ {
[JsonIgnore] public long ID { get; set; } [JsonIgnore] public int ID { get; set; }
[JsonIgnore] public long ProviderID { get; set; } [JsonIgnore] public int ProviderID { get; set; }
public virtual ProviderID Provider {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 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 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 virtual Season Season { get; set; }
[JsonIgnore] public long? PeopleID { get; set; } [JsonIgnore] public int? PeopleID { get; set; }
[JsonIgnore] public virtual People People { get; set; } [JsonIgnore] public virtual People People { get; set; }
public string DataID { get; set; } public string DataID { get; set; }

View File

@ -6,7 +6,7 @@ namespace Kyoo.Models
{ {
public class People public class People
{ {
public long ID { get; set; } public int ID { get; set; }
public string Slug { get; set; } public string Slug { get; set; }
public string Name { get; set; } public string Name { get; set; }
[JsonIgnore] public string ImgPrimary { get; set; } [JsonIgnore] public string ImgPrimary { get; set; }

View File

@ -5,8 +5,8 @@ namespace Kyoo.Models
{ {
public class PeopleLink public class PeopleLink
{ {
[JsonIgnore] public long ID { get; set; } [JsonIgnore] public int ID { get; set; }
[JsonIgnore] public long PeopleID { get; set; } [JsonIgnore] public int PeopleID { get; set; }
[JsonIgnore] public virtual People People { get; set; } [JsonIgnore] public virtual People People { get; set; }
public string Slug public string Slug
@ -27,7 +27,7 @@ namespace Kyoo.Models
set => People.ExternalIDs = value; set => People.ExternalIDs = value;
} }
[JsonIgnore] public long ShowID { get; set; } [JsonIgnore] public int ShowID { get; set; }
[JsonIgnore] public virtual Show Show { get; set; } [JsonIgnore] public virtual Show Show { get; set; }
public string Role { get; set; } public string Role { get; set; }
public string Type { get; set; } public string Type { get; set; }

View File

@ -4,13 +4,13 @@ namespace Kyoo.Models
{ {
public class ProviderID public class ProviderID
{ {
[JsonIgnore] public long ID { get; set; } [JsonIgnore] public int ID { get; set; }
public string Name { get; set; } public string Name { get; set; }
public string Logo { get; set; } public string Logo { get; set; }
public ProviderID() { } public ProviderID() { }
public ProviderID(long id, string name, string logo) public ProviderID(int id, string name, string logo)
{ {
ID = id; ID = id;
Name = name; Name = name;

View File

@ -4,10 +4,10 @@ namespace Kyoo.Models
{ {
public class ProviderLink public class ProviderLink
{ {
[JsonIgnore] public long ID { get; set; } [JsonIgnore] public int ID { get; set; }
[JsonIgnore] public long ProviderID { get; set; } [JsonIgnore] public int ProviderID { get; set; }
[JsonIgnore] public virtual ProviderID Provider { 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; } [JsonIgnore] public virtual Library Library { get; set; }
public ProviderLink() { } public ProviderLink() { }

View File

@ -5,15 +5,15 @@ namespace Kyoo.Models
{ {
public class Season public class Season
{ {
[JsonIgnore] public long ID { get; set; } [JsonIgnore] public int ID { get; set; }
[JsonIgnore] public long ShowID { 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 Title { get; set; }
public string Overview { get; set; } public string Overview { get; set; }
public long? Year { get; set; } public int? Year { get; set; }
[JsonIgnore] public string ImgPrimary { get; set; } [JsonIgnore] public string ImgPrimary { get; set; }
public virtual IEnumerable<MetadataID> ExternalIDs { get; set; } public virtual IEnumerable<MetadataID> ExternalIDs { get; set; }
@ -23,11 +23,11 @@ namespace Kyoo.Models
public Season() { } public Season() { }
public Season(long showID, public Season(int showID,
long seasonNumber, int seasonNumber,
string title, string title,
string overview, string overview,
long? year, int? year,
string imgPrimary, string imgPrimary,
IEnumerable<MetadataID> externalIDs) IEnumerable<MetadataID> externalIDs)
{ {

View File

@ -7,7 +7,7 @@ namespace Kyoo.Models
{ {
public class Show : IOnMerge public class Show : IOnMerge
{ {
[JsonIgnore] public long ID { get; set; } [JsonIgnore] public int ID { get; set; }
public string Slug { get; set; } public string Slug { get; set; }
public string Title { get; set; } public string Title { get; set; }
@ -17,8 +17,8 @@ namespace Kyoo.Models
public Status? Status { get; set; } public Status? Status { get; set; }
public string TrailerUrl { get; set; } public string TrailerUrl { get; set; }
public long? StartYear { get; set; } public int? StartYear { get; set; }
public long? EndYear { get; set; } public int? EndYear { get; set; }
public string Poster { get; set; } public string Poster { get; set; }
public string Logo { get; set; } public string Logo { get; set; }
@ -36,6 +36,7 @@ namespace Kyoo.Models
set => GenreLinks = value?.Select(x => new GenreLink(this, x)).ToList(); set => GenreLinks = value?.Select(x => new GenreLink(this, x)).ToList();
} }
[NotMergable] [JsonIgnore] public virtual IEnumerable<GenreLink> GenreLinks { get; set; } [NotMergable] [JsonIgnore] public virtual IEnumerable<GenreLink> GenreLinks { get; set; }
[JsonIgnore] public int? StudioID { get; set; }
public virtual Studio Studio { get; set; } public virtual Studio Studio { get; set; }
[JsonIgnore] public virtual IEnumerable<PeopleLink> People { get; set; } [JsonIgnore] public virtual IEnumerable<PeopleLink> People { get; set; }
[JsonIgnore] public virtual IEnumerable<Season> Seasons { get; set; } [JsonIgnore] public virtual IEnumerable<Season> Seasons { get; set; }
@ -50,8 +51,8 @@ namespace Kyoo.Models
string trailerUrl, string trailerUrl,
IEnumerable<Genre> genres, IEnumerable<Genre> genres,
Status? status, Status? status,
long? startYear, int? startYear,
long? endYear, int? endYear,
IEnumerable<MetadataID> externalIDs) IEnumerable<MetadataID> externalIDs)
{ {
Slug = slug; Slug = slug;
@ -75,8 +76,8 @@ namespace Kyoo.Models
string overview, string overview,
string trailerUrl, string trailerUrl,
Status? status, Status? status,
long? startYear, int? startYear,
long? endYear, int? endYear,
string poster, string poster,
string logo, string logo,
string backdrop, string backdrop,

View File

@ -5,7 +5,7 @@ namespace Kyoo.Models
{ {
public class Studio public class Studio
{ {
[JsonIgnore] public long ID { get; set; } [JsonIgnore] public int ID { get; set; }
public string Slug { get; set; } public string Slug { get; set; }
public string Name { get; set; } public string Name { get; set; }

View File

@ -14,7 +14,7 @@ namespace Kyoo.Models
public bool RunOnStartup { get; } public bool RunOnStartup { get; }
public int Priority { get; } public int Priority { get; }
public Task Run(IServiceProvider serviceProvider, CancellationToken cancellationToken, string arguments = null); public Task Run(IServiceProvider serviceProvider, CancellationToken cancellationToken, string arguments = null);
public IEnumerable<string> GetPossibleParameters(); public Task<IEnumerable<string>> GetPossibleParameters();
public int? Progress(); public int? Progress();
} }
} }

View File

@ -55,8 +55,8 @@ namespace Kyoo.Models
public class Track : Stream public class Track : Stream
{ {
[JsonIgnore] public long ID { get; set; } [JsonIgnore] public int ID { get; set; }
[JsonIgnore] public long EpisodeID { get; set; } [JsonIgnore] public int EpisodeID { get; set; }
public bool IsDefault public bool IsDefault
{ {
get => isDefault; get => isDefault;

View File

@ -7,12 +7,12 @@ namespace Kyoo.Models
{ {
public class WatchItem public class WatchItem
{ {
[JsonIgnore] public readonly long EpisodeID = -1; [JsonIgnore] public readonly int EpisodeID = -1;
public string ShowTitle; public string ShowTitle;
public string ShowSlug; public string ShowSlug;
public long SeasonNumber; public int SeasonNumber;
public long EpisodeNumber; public int EpisodeNumber;
public string Title; public string Title;
public string Link; public string Link;
public DateTime? ReleaseDate; public DateTime? ReleaseDate;
@ -28,11 +28,11 @@ namespace Kyoo.Models
public WatchItem() { } public WatchItem() { }
public WatchItem(long episodeID, public WatchItem(int episodeID,
string showTitle, string showTitle,
string showSlug, string showSlug,
long seasonNumber, int seasonNumber,
long episodeNumber, int episodeNumber,
string title, string title,
DateTime? releaseDate, DateTime? releaseDate,
string path) string path)
@ -50,11 +50,11 @@ namespace Kyoo.Models
Link = Episode.GetSlug(ShowSlug, seasonNumber, episodeNumber); Link = Episode.GetSlug(ShowSlug, seasonNumber, episodeNumber);
} }
public WatchItem(long episodeID, public WatchItem(int episodeID,
string showTitle, string showTitle,
string showSlug, string showSlug,
long seasonNumber, int seasonNumber,
long episodeNumber, int episodeNumber,
string title, string title,
DateTime? releaseDate, DateTime? releaseDate,
string path, string path,

View File

@ -1,394 +1,366 @@
using System; using System;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Kyoo.Models; using Kyoo.Models;
using Kyoo.Models.Exceptions;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
namespace Kyoo.Controllers namespace Kyoo.Controllers
{ {
public class LibraryManager : ILibraryManager public class LibraryManager : ILibraryManager
{ {
private const int MaxSaveRetry = 3; private readonly ILibraryRepository _libraries;
private readonly DatabaseContext _database; private readonly ICollectionRepository _collections;
private readonly IShowRepository _shows;
private readonly ISeasonRepository _seasons;
private readonly IEpisodeRepository _episodes;
private readonly ITrackRepository _tracks;
private readonly IGenreRepository _genres;
private readonly IStudioRepository _studios;
private readonly IPeopleRepository _people;
private readonly IProviderRepository _providers;
public LibraryManager(ILibraryRepository libraries,
public LibraryManager(DatabaseContext database) 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 Task<Library> GetLibrary(string slug)
public Library GetLibrary(string librarySlug)
{ {
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 return _people.Get(slug);
&& x.SeasonNumber == seasonNumber }
&& x.Show.Slug == showSlug);
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 public Task<ICollection<Genre>> SearchGenres(string searchQuery)
#region GetAll
public IEnumerable<Library> GetLibraries()
{ {
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; return _libraries.Create(library);
}
public IEnumerable<Genre> GetGenres()
{
return _database.Genres;
}
public IEnumerable<Studio> GetStudios()
{
return _database.Studios;
} }
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 public Task RegisterSeason(Season season)
#region GetHelper
public IEnumerable<string> GetLibrariesPath()
{ {
IEnumerable<string> paths = new List<string>(); return _seasons.Create(season);
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);
} }
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); return _episodes.Create(episode);
}
#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);
} }
public IEnumerable<Genre> SearchGenres(string searchQuery) public Task RegisterTrack(Track track)
{ {
return _database.Genres.Where(genre => EF.Functions.Like(genre.Name, $"%{searchQuery}%")) return _tracks.Create(track);
.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;
});
} }
public void RegisterShowLinks(Library library, Collection collection, Show show) public Task RegisterGenre(Genre genre)
{ {
if (collection != null) return _genres.Create(genre);
{
_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);
} }
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(); return _people.Create(people);
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);
}
} }
private void ValidateNavigation(NavigationEntry navigation) public Task EditLibrary(Library library, bool resetOld)
{ {
object oldValue = navigation.CurrentValue; return _libraries.Edit(library, resetOld);
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);
} }
public IEnumerable<T> ValidateList<T>(IEnumerable<T> list) where T : class public Task EditCollection(Collection collection, bool resetOld)
{ {
return list.Select(x => return _collections.Edit(collection, resetOld);
{
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();
} }
private object FindExisting(object obj) public Task EditShow(Show show, bool resetOld)
{ {
return obj switch return _shows.Edit(show, resetOld);
{
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
};
} }
public IEnumerable<MetadataID> Validate(IEnumerable<MetadataID> ids) public Task EditSeason(Season season, bool resetOld)
{ {
return ids?.Select(x => return _seasons.Edit(season, resetOld);
{
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);
} }
public void RemoveSeason(Season season) public Task EditEpisode(Episode episode, bool resetOld)
{ {
if (_database.Entry(season).State == EntityState.Detached) return _episodes.Edit(episode, resetOld);
_database.Seasons.Attach(season);
_database.Seasons.Remove(season);
} }
public void RemoveEpisode(Episode episode) public Task EditTrack(Track track, bool resetOld)
{ {
if (_database.Entry(episode).State == EntityState.Detached) return _tracks.Edit(track, resetOld);
_database.Episodes.Attach(episode); }
_database.Episodes.Remove(episode);
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
} }
} }

View File

@ -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( Season season = await GetMetadata(
provider => provider.GetSeason(show, seasonNumber), provider => provider.GetSeason(show, seasonNumber),
library, library,
$"the season {seasonNumber} of {show.Title}"); $"the season {seasonNumber} of {show.Title}");
season.Show = show; season.Show = show;
season.ShowID = show.ID;
season.SeasonNumber = season.SeasonNumber == -1 ? seasonNumber : season.SeasonNumber; season.SeasonNumber = season.SeasonNumber == -1 ? seasonNumber : season.SeasonNumber;
season.Title ??= $"Season {season.SeasonNumber}"; season.Title ??= $"Season {season.SeasonNumber}";
return season; return season;
@ -127,9 +128,9 @@ namespace Kyoo.Controllers
public async Task<Episode> GetEpisode(Show show, public async Task<Episode> GetEpisode(Show show,
string episodePath, string episodePath,
long seasonNumber, int seasonNumber,
long episodeNumber, int episodeNumber,
long absoluteNumber, int absoluteNumber,
Library library) Library library)
{ {
Episode episode = await GetMetadata( Episode episode = await GetMetadata(
@ -137,6 +138,7 @@ namespace Kyoo.Controllers
library, library,
"an episode"); "an episode");
episode.Show = show; episode.Show = show;
episode.ShowID = show.ID;
episode.Path = episodePath; episode.Path = episodePath;
episode.SeasonNumber = episode.SeasonNumber != -1 ? episode.SeasonNumber : seasonNumber; episode.SeasonNumber = episode.SeasonNumber != -1 ? episode.SeasonNumber : seasonNumber;
episode.EpisodeNumber = episode.EpisodeNumber != -1 ? episode.EpisodeNumber : episodeNumber; episode.EpisodeNumber = episode.EpisodeNumber != -1 ? episode.EpisodeNumber : episodeNumber;
@ -155,6 +157,7 @@ namespace Kyoo.Controllers
.Select(x => .Select(x =>
{ {
x.Show = show; x.Show = show;
x.ShowID = show.ID;
return x; return x;
}).ToList(); }).ToList();
} }

View 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();
}
}
}

View 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();
}
}
}

View 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();
}
}
}

View 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();
}
}
}

View 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();
}
}
}

View 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();
}
}
}

View 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();
}
}
}

View 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();
}
}
}

View 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();
}
}
}

View 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();
}
}
}

View File

@ -10,7 +10,7 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace Kyoo.Models.DatabaseMigrations.Internal namespace Kyoo.Models.DatabaseMigrations.Internal
{ {
[DbContext(typeof(DatabaseContext))] [DbContext(typeof(DatabaseContext))]
[Migration("20200526235513_Initial")] [Migration("20200607010830_Initial")]
partial class Initial partial class Initial
{ {
protected override void BuildTargetModel(ModelBuilder modelBuilder) protected override void BuildTargetModel(ModelBuilder modelBuilder)
@ -23,9 +23,9 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
modelBuilder.Entity("Kyoo.Models.Collection", b => modelBuilder.Entity("Kyoo.Models.Collection", b =>
{ {
b.Property<long>("ID") b.Property<int>("ID")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("bigint") .HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("ImgPrimary") b.Property<string>("ImgPrimary")
@ -53,16 +53,16 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
modelBuilder.Entity("Kyoo.Models.CollectionLink", b => modelBuilder.Entity("Kyoo.Models.CollectionLink", b =>
{ {
b.Property<long>("ID") b.Property<int>("ID")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("bigint") .HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<long?>("CollectionID") b.Property<int?>("CollectionID")
.HasColumnType("bigint"); .HasColumnType("integer");
b.Property<long>("ShowID") b.Property<int>("ShowID")
.HasColumnType("bigint"); .HasColumnType("integer");
b.HasKey("ID"); b.HasKey("ID");
@ -75,16 +75,16 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
modelBuilder.Entity("Kyoo.Models.Episode", b => modelBuilder.Entity("Kyoo.Models.Episode", b =>
{ {
b.Property<long>("ID") b.Property<int>("ID")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("bigint") .HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<long>("AbsoluteNumber") b.Property<int>("AbsoluteNumber")
.HasColumnType("bigint"); .HasColumnType("integer");
b.Property<long>("EpisodeNumber") b.Property<int>("EpisodeNumber")
.HasColumnType("bigint"); .HasColumnType("integer");
b.Property<string>("ImgPrimary") b.Property<string>("ImgPrimary")
.HasColumnType("text"); .HasColumnType("text");
@ -98,17 +98,17 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
b.Property<DateTime?>("ReleaseDate") b.Property<DateTime?>("ReleaseDate")
.HasColumnType("timestamp without time zone"); .HasColumnType("timestamp without time zone");
b.Property<long>("Runtime") b.Property<int>("Runtime")
.HasColumnType("bigint"); .HasColumnType("integer");
b.Property<long?>("SeasonID") b.Property<int?>("SeasonID")
.HasColumnType("bigint"); .HasColumnType("integer");
b.Property<long>("SeasonNumber") b.Property<int>("SeasonNumber")
.HasColumnType("bigint"); .HasColumnType("integer");
b.Property<long>("ShowID") b.Property<int>("ShowID")
.HasColumnType("bigint"); .HasColumnType("integer");
b.Property<string>("Title") b.Property<string>("Title")
.HasColumnType("text"); .HasColumnType("text");
@ -124,9 +124,9 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
modelBuilder.Entity("Kyoo.Models.Genre", b => modelBuilder.Entity("Kyoo.Models.Genre", b =>
{ {
b.Property<long>("ID") b.Property<int>("ID")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("bigint") .HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("Name") b.Property<string>("Name")
@ -145,11 +145,11 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
modelBuilder.Entity("Kyoo.Models.GenreLink", b => modelBuilder.Entity("Kyoo.Models.GenreLink", b =>
{ {
b.Property<long>("ShowID") b.Property<int>("ShowID")
.HasColumnType("bigint"); .HasColumnType("integer");
b.Property<long>("GenreID") b.Property<int>("GenreID")
.HasColumnType("bigint"); .HasColumnType("integer");
b.HasKey("ShowID", "GenreID"); b.HasKey("ShowID", "GenreID");
@ -160,9 +160,9 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
modelBuilder.Entity("Kyoo.Models.Library", b => modelBuilder.Entity("Kyoo.Models.Library", b =>
{ {
b.Property<long>("ID") b.Property<int>("ID")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("bigint") .HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("Name") b.Property<string>("Name")
@ -184,19 +184,19 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
modelBuilder.Entity("Kyoo.Models.LibraryLink", b => modelBuilder.Entity("Kyoo.Models.LibraryLink", b =>
{ {
b.Property<long>("ID") b.Property<int>("ID")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("bigint") .HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<long?>("CollectionID") b.Property<int?>("CollectionID")
.HasColumnType("bigint"); .HasColumnType("integer");
b.Property<long>("LibraryID") b.Property<int>("LibraryID")
.HasColumnType("bigint"); .HasColumnType("integer");
b.Property<long?>("ShowID") b.Property<int?>("ShowID")
.HasColumnType("bigint"); .HasColumnType("integer");
b.HasKey("ID"); b.HasKey("ID");
@ -211,31 +211,31 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
modelBuilder.Entity("Kyoo.Models.MetadataID", b => modelBuilder.Entity("Kyoo.Models.MetadataID", b =>
{ {
b.Property<long>("ID") b.Property<int>("ID")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("bigint") .HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("DataID") b.Property<string>("DataID")
.HasColumnType("text"); .HasColumnType("text");
b.Property<long?>("EpisodeID") b.Property<int?>("EpisodeID")
.HasColumnType("bigint"); .HasColumnType("integer");
b.Property<string>("Link") b.Property<string>("Link")
.HasColumnType("text"); .HasColumnType("text");
b.Property<long?>("PeopleID") b.Property<int?>("PeopleID")
.HasColumnType("bigint"); .HasColumnType("integer");
b.Property<long>("ProviderID") b.Property<int>("ProviderID")
.HasColumnType("bigint"); .HasColumnType("integer");
b.Property<long?>("SeasonID") b.Property<int?>("SeasonID")
.HasColumnType("bigint"); .HasColumnType("integer");
b.Property<long?>("ShowID") b.Property<int?>("ShowID")
.HasColumnType("bigint"); .HasColumnType("integer");
b.HasKey("ID"); b.HasKey("ID");
@ -254,9 +254,9 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
modelBuilder.Entity("Kyoo.Models.People", b => modelBuilder.Entity("Kyoo.Models.People", b =>
{ {
b.Property<long>("ID") b.Property<int>("ID")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("bigint") .HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("ImgPrimary") b.Property<string>("ImgPrimary")
@ -278,19 +278,19 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
modelBuilder.Entity("Kyoo.Models.PeopleLink", b => modelBuilder.Entity("Kyoo.Models.PeopleLink", b =>
{ {
b.Property<long>("ID") b.Property<int>("ID")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("bigint") .HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<long>("PeopleID") b.Property<int>("PeopleID")
.HasColumnType("bigint"); .HasColumnType("integer");
b.Property<string>("Role") b.Property<string>("Role")
.HasColumnType("text"); .HasColumnType("text");
b.Property<long>("ShowID") b.Property<int>("ShowID")
.HasColumnType("bigint"); .HasColumnType("integer");
b.Property<string>("Type") b.Property<string>("Type")
.HasColumnType("text"); .HasColumnType("text");
@ -306,9 +306,9 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
modelBuilder.Entity("Kyoo.Models.ProviderID", b => modelBuilder.Entity("Kyoo.Models.ProviderID", b =>
{ {
b.Property<long>("ID") b.Property<int>("ID")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("bigint") .HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("Logo") b.Property<string>("Logo")
@ -327,16 +327,16 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
modelBuilder.Entity("Kyoo.Models.ProviderLink", b => modelBuilder.Entity("Kyoo.Models.ProviderLink", b =>
{ {
b.Property<long>("ID") b.Property<int>("ID")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("bigint") .HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<long?>("LibraryID") b.Property<int?>("LibraryID")
.HasColumnType("bigint"); .HasColumnType("integer");
b.Property<long>("ProviderID") b.Property<int>("ProviderID")
.HasColumnType("bigint"); .HasColumnType("integer");
b.HasKey("ID"); b.HasKey("ID");
@ -349,9 +349,9 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
modelBuilder.Entity("Kyoo.Models.Season", b => modelBuilder.Entity("Kyoo.Models.Season", b =>
{ {
b.Property<long>("ID") b.Property<int>("ID")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("bigint") .HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("ImgPrimary") b.Property<string>("ImgPrimary")
@ -360,17 +360,17 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
b.Property<string>("Overview") b.Property<string>("Overview")
.HasColumnType("text"); .HasColumnType("text");
b.Property<long>("SeasonNumber") b.Property<int>("SeasonNumber")
.HasColumnType("bigint"); .HasColumnType("integer");
b.Property<long>("ShowID") b.Property<int>("ShowID")
.HasColumnType("bigint"); .HasColumnType("integer");
b.Property<string>("Title") b.Property<string>("Title")
.HasColumnType("text"); .HasColumnType("text");
b.Property<long?>("Year") b.Property<int?>("Year")
.HasColumnType("bigint"); .HasColumnType("integer");
b.HasKey("ID"); b.HasKey("ID");
@ -381,9 +381,9 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
modelBuilder.Entity("Kyoo.Models.Show", b => modelBuilder.Entity("Kyoo.Models.Show", b =>
{ {
b.Property<long>("ID") b.Property<int>("ID")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("bigint") .HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("Aliases") b.Property<string>("Aliases")
@ -392,8 +392,8 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
b.Property<string>("Backdrop") b.Property<string>("Backdrop")
.HasColumnType("text"); .HasColumnType("text");
b.Property<long?>("EndYear") b.Property<int?>("EndYear")
.HasColumnType("bigint"); .HasColumnType("integer");
b.Property<bool>("IsMovie") b.Property<bool>("IsMovie")
.HasColumnType("boolean"); .HasColumnType("boolean");
@ -413,14 +413,14 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
b.Property<string>("Slug") b.Property<string>("Slug")
.HasColumnType("text"); .HasColumnType("text");
b.Property<long?>("StartYear") b.Property<int?>("StartYear")
.HasColumnType("bigint"); .HasColumnType("integer");
b.Property<int?>("Status") b.Property<int?>("Status")
.HasColumnType("integer"); .HasColumnType("integer");
b.Property<long?>("StudioID") b.Property<int?>("StudioID")
.HasColumnType("bigint"); .HasColumnType("integer");
b.Property<string>("Title") b.Property<string>("Title")
.HasColumnType("text"); .HasColumnType("text");
@ -440,9 +440,9 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
modelBuilder.Entity("Kyoo.Models.Studio", b => modelBuilder.Entity("Kyoo.Models.Studio", b =>
{ {
b.Property<long>("ID") b.Property<int>("ID")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("bigint") .HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("Name") b.Property<string>("Name")
@ -461,16 +461,16 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
modelBuilder.Entity("Kyoo.Models.Track", b => modelBuilder.Entity("Kyoo.Models.Track", b =>
{ {
b.Property<long>("ID") b.Property<int>("ID")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("bigint") .HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("Codec") b.Property<string>("Codec")
.HasColumnType("text"); .HasColumnType("text");
b.Property<long>("EpisodeID") b.Property<int>("EpisodeID")
.HasColumnType("bigint"); .HasColumnType("integer");
b.Property<bool>("IsDefault") b.Property<bool>("IsDefault")
.HasColumnType("boolean"); .HasColumnType("boolean");

View File

@ -12,7 +12,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
name: "Collections", name: "Collections",
columns: table => new columns: table => new
{ {
ID = table.Column<long>(nullable: false) ID = table.Column<int>(nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Slug = table.Column<string>(nullable: true), Slug = table.Column<string>(nullable: true),
Name = table.Column<string>(nullable: true), Name = table.Column<string>(nullable: true),
@ -29,7 +29,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
name: "Genres", name: "Genres",
columns: table => new columns: table => new
{ {
ID = table.Column<long>(nullable: false) ID = table.Column<int>(nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Slug = table.Column<string>(nullable: true), Slug = table.Column<string>(nullable: true),
Name = table.Column<string>(nullable: true) Name = table.Column<string>(nullable: true)
@ -43,7 +43,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
name: "Libraries", name: "Libraries",
columns: table => new columns: table => new
{ {
ID = table.Column<long>(nullable: false) ID = table.Column<int>(nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Slug = table.Column<string>(nullable: true), Slug = table.Column<string>(nullable: true),
Name = table.Column<string>(nullable: true), Name = table.Column<string>(nullable: true),
@ -58,7 +58,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
name: "Peoples", name: "Peoples",
columns: table => new columns: table => new
{ {
ID = table.Column<long>(nullable: false) ID = table.Column<int>(nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Slug = table.Column<string>(nullable: true), Slug = table.Column<string>(nullable: true),
Name = table.Column<string>(nullable: true), Name = table.Column<string>(nullable: true),
@ -73,7 +73,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
name: "Providers", name: "Providers",
columns: table => new columns: table => new
{ {
ID = table.Column<long>(nullable: false) ID = table.Column<int>(nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Name = table.Column<string>(nullable: true), Name = table.Column<string>(nullable: true),
Logo = table.Column<string>(nullable: true) Logo = table.Column<string>(nullable: true)
@ -87,7 +87,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
name: "Studios", name: "Studios",
columns: table => new columns: table => new
{ {
ID = table.Column<long>(nullable: false) ID = table.Column<int>(nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Slug = table.Column<string>(nullable: true), Slug = table.Column<string>(nullable: true),
Name = table.Column<string>(nullable: true) Name = table.Column<string>(nullable: true)
@ -101,10 +101,10 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
name: "ProviderLinks", name: "ProviderLinks",
columns: table => new columns: table => new
{ {
ID = table.Column<long>(nullable: false) ID = table.Column<int>(nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
ProviderID = table.Column<long>(nullable: false), ProviderID = table.Column<int>(nullable: false),
LibraryID = table.Column<long>(nullable: true) LibraryID = table.Column<int>(nullable: true)
}, },
constraints: table => constraints: table =>
{ {
@ -127,7 +127,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
name: "Shows", name: "Shows",
columns: table => new columns: table => new
{ {
ID = table.Column<long>(nullable: false) ID = table.Column<int>(nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Slug = table.Column<string>(nullable: true), Slug = table.Column<string>(nullable: true),
Title = 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), Overview = table.Column<string>(nullable: true),
Status = table.Column<int>(nullable: true), Status = table.Column<int>(nullable: true),
TrailerUrl = table.Column<string>(nullable: true), TrailerUrl = table.Column<string>(nullable: true),
StartYear = table.Column<long>(nullable: true), StartYear = table.Column<int>(nullable: true),
EndYear = table.Column<long>(nullable: true), EndYear = table.Column<int>(nullable: true),
Poster = table.Column<string>(nullable: true), Poster = table.Column<string>(nullable: true),
Logo = table.Column<string>(nullable: true), Logo = table.Column<string>(nullable: true),
Backdrop = table.Column<string>(nullable: true), Backdrop = table.Column<string>(nullable: true),
IsMovie = table.Column<bool>(nullable: false), IsMovie = table.Column<bool>(nullable: false),
StudioID = table.Column<long>(nullable: true) StudioID = table.Column<int>(nullable: true)
}, },
constraints: table => constraints: table =>
{ {
@ -159,10 +159,10 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
name: "CollectionLinks", name: "CollectionLinks",
columns: table => new columns: table => new
{ {
ID = table.Column<long>(nullable: false) ID = table.Column<int>(nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
CollectionID = table.Column<long>(nullable: true), CollectionID = table.Column<int>(nullable: true),
ShowID = table.Column<long>(nullable: false) ShowID = table.Column<int>(nullable: false)
}, },
constraints: table => constraints: table =>
{ {
@ -185,8 +185,8 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
name: "GenreLinks", name: "GenreLinks",
columns: table => new columns: table => new
{ {
ShowID = table.Column<long>(nullable: false), ShowID = table.Column<int>(nullable: false),
GenreID = table.Column<long>(nullable: false) GenreID = table.Column<int>(nullable: false)
}, },
constraints: table => constraints: table =>
{ {
@ -209,11 +209,11 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
name: "LibraryLinks", name: "LibraryLinks",
columns: table => new columns: table => new
{ {
ID = table.Column<long>(nullable: false) ID = table.Column<int>(nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
LibraryID = table.Column<long>(nullable: false), LibraryID = table.Column<int>(nullable: false),
ShowID = table.Column<long>(nullable: true), ShowID = table.Column<int>(nullable: true),
CollectionID = table.Column<long>(nullable: true) CollectionID = table.Column<int>(nullable: true)
}, },
constraints: table => constraints: table =>
{ {
@ -242,10 +242,10 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
name: "PeopleLinks", name: "PeopleLinks",
columns: table => new columns: table => new
{ {
ID = table.Column<long>(nullable: false) ID = table.Column<int>(nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
PeopleID = table.Column<long>(nullable: false), PeopleID = table.Column<int>(nullable: false),
ShowID = table.Column<long>(nullable: false), ShowID = table.Column<int>(nullable: false),
Role = table.Column<string>(nullable: true), Role = table.Column<string>(nullable: true),
Type = table.Column<string>(nullable: true) Type = table.Column<string>(nullable: true)
}, },
@ -270,13 +270,13 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
name: "Seasons", name: "Seasons",
columns: table => new columns: table => new
{ {
ID = table.Column<long>(nullable: false) ID = table.Column<int>(nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
ShowID = table.Column<long>(nullable: false), ShowID = table.Column<int>(nullable: false),
SeasonNumber = table.Column<long>(nullable: false), SeasonNumber = table.Column<int>(nullable: false),
Title = table.Column<string>(nullable: true), Title = table.Column<string>(nullable: true),
Overview = 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) ImgPrimary = table.Column<string>(nullable: true)
}, },
constraints: table => constraints: table =>
@ -294,18 +294,18 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
name: "Episodes", name: "Episodes",
columns: table => new columns: table => new
{ {
ID = table.Column<long>(nullable: false) ID = table.Column<int>(nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
ShowID = table.Column<long>(nullable: false), ShowID = table.Column<int>(nullable: false),
SeasonID = table.Column<long>(nullable: true), SeasonID = table.Column<int>(nullable: true),
SeasonNumber = table.Column<long>(nullable: false), SeasonNumber = table.Column<int>(nullable: false),
EpisodeNumber = table.Column<long>(nullable: false), EpisodeNumber = table.Column<int>(nullable: false),
AbsoluteNumber = table.Column<long>(nullable: false), AbsoluteNumber = table.Column<int>(nullable: false),
Path = table.Column<string>(nullable: true), Path = table.Column<string>(nullable: true),
Title = table.Column<string>(nullable: true), Title = table.Column<string>(nullable: true),
Overview = table.Column<string>(nullable: true), Overview = table.Column<string>(nullable: true),
ReleaseDate = table.Column<DateTime>(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) ImgPrimary = table.Column<string>(nullable: true)
}, },
constraints: table => constraints: table =>
@ -329,13 +329,13 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
name: "MetadataIds", name: "MetadataIds",
columns: table => new columns: table => new
{ {
ID = table.Column<long>(nullable: false) ID = table.Column<int>(nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
ProviderID = table.Column<long>(nullable: false), ProviderID = table.Column<int>(nullable: false),
ShowID = table.Column<long>(nullable: true), ShowID = table.Column<int>(nullable: true),
EpisodeID = table.Column<long>(nullable: true), EpisodeID = table.Column<int>(nullable: true),
SeasonID = table.Column<long>(nullable: true), SeasonID = table.Column<int>(nullable: true),
PeopleID = table.Column<long>(nullable: true), PeopleID = table.Column<int>(nullable: true),
DataID = table.Column<string>(nullable: true), DataID = table.Column<string>(nullable: true),
Link = table.Column<string>(nullable: true) Link = table.Column<string>(nullable: true)
}, },
@ -378,14 +378,14 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
name: "Tracks", name: "Tracks",
columns: table => new columns: table => new
{ {
ID = table.Column<long>(nullable: false) ID = table.Column<int>(nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Title = table.Column<string>(nullable: true), Title = table.Column<string>(nullable: true),
Language = table.Column<string>(nullable: true), Language = table.Column<string>(nullable: true),
Codec = table.Column<string>(nullable: true), Codec = table.Column<string>(nullable: true),
Path = table.Column<string>(nullable: true), Path = table.Column<string>(nullable: true),
Type = table.Column<int>(nullable: false), Type = table.Column<int>(nullable: false),
EpisodeID = table.Column<long>(nullable: false), EpisodeID = table.Column<int>(nullable: false),
IsDefault = table.Column<bool>(nullable: false), IsDefault = table.Column<bool>(nullable: false),
IsForced = table.Column<bool>(nullable: false), IsForced = table.Column<bool>(nullable: false),
IsExternal = table.Column<bool>(nullable: false) IsExternal = table.Column<bool>(nullable: false)

View File

@ -21,9 +21,9 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
modelBuilder.Entity("Kyoo.Models.Collection", b => modelBuilder.Entity("Kyoo.Models.Collection", b =>
{ {
b.Property<long>("ID") b.Property<int>("ID")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("bigint") .HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("ImgPrimary") b.Property<string>("ImgPrimary")
@ -51,16 +51,16 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
modelBuilder.Entity("Kyoo.Models.CollectionLink", b => modelBuilder.Entity("Kyoo.Models.CollectionLink", b =>
{ {
b.Property<long>("ID") b.Property<int>("ID")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("bigint") .HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<long?>("CollectionID") b.Property<int?>("CollectionID")
.HasColumnType("bigint"); .HasColumnType("integer");
b.Property<long>("ShowID") b.Property<int>("ShowID")
.HasColumnType("bigint"); .HasColumnType("integer");
b.HasKey("ID"); b.HasKey("ID");
@ -73,16 +73,16 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
modelBuilder.Entity("Kyoo.Models.Episode", b => modelBuilder.Entity("Kyoo.Models.Episode", b =>
{ {
b.Property<long>("ID") b.Property<int>("ID")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("bigint") .HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<long>("AbsoluteNumber") b.Property<int>("AbsoluteNumber")
.HasColumnType("bigint"); .HasColumnType("integer");
b.Property<long>("EpisodeNumber") b.Property<int>("EpisodeNumber")
.HasColumnType("bigint"); .HasColumnType("integer");
b.Property<string>("ImgPrimary") b.Property<string>("ImgPrimary")
.HasColumnType("text"); .HasColumnType("text");
@ -96,17 +96,17 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
b.Property<DateTime?>("ReleaseDate") b.Property<DateTime?>("ReleaseDate")
.HasColumnType("timestamp without time zone"); .HasColumnType("timestamp without time zone");
b.Property<long>("Runtime") b.Property<int>("Runtime")
.HasColumnType("bigint"); .HasColumnType("integer");
b.Property<long?>("SeasonID") b.Property<int?>("SeasonID")
.HasColumnType("bigint"); .HasColumnType("integer");
b.Property<long>("SeasonNumber") b.Property<int>("SeasonNumber")
.HasColumnType("bigint"); .HasColumnType("integer");
b.Property<long>("ShowID") b.Property<int>("ShowID")
.HasColumnType("bigint"); .HasColumnType("integer");
b.Property<string>("Title") b.Property<string>("Title")
.HasColumnType("text"); .HasColumnType("text");
@ -122,9 +122,9 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
modelBuilder.Entity("Kyoo.Models.Genre", b => modelBuilder.Entity("Kyoo.Models.Genre", b =>
{ {
b.Property<long>("ID") b.Property<int>("ID")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("bigint") .HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("Name") b.Property<string>("Name")
@ -143,11 +143,11 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
modelBuilder.Entity("Kyoo.Models.GenreLink", b => modelBuilder.Entity("Kyoo.Models.GenreLink", b =>
{ {
b.Property<long>("ShowID") b.Property<int>("ShowID")
.HasColumnType("bigint"); .HasColumnType("integer");
b.Property<long>("GenreID") b.Property<int>("GenreID")
.HasColumnType("bigint"); .HasColumnType("integer");
b.HasKey("ShowID", "GenreID"); b.HasKey("ShowID", "GenreID");
@ -158,9 +158,9 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
modelBuilder.Entity("Kyoo.Models.Library", b => modelBuilder.Entity("Kyoo.Models.Library", b =>
{ {
b.Property<long>("ID") b.Property<int>("ID")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("bigint") .HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("Name") b.Property<string>("Name")
@ -182,19 +182,19 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
modelBuilder.Entity("Kyoo.Models.LibraryLink", b => modelBuilder.Entity("Kyoo.Models.LibraryLink", b =>
{ {
b.Property<long>("ID") b.Property<int>("ID")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("bigint") .HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<long?>("CollectionID") b.Property<int?>("CollectionID")
.HasColumnType("bigint"); .HasColumnType("integer");
b.Property<long>("LibraryID") b.Property<int>("LibraryID")
.HasColumnType("bigint"); .HasColumnType("integer");
b.Property<long?>("ShowID") b.Property<int?>("ShowID")
.HasColumnType("bigint"); .HasColumnType("integer");
b.HasKey("ID"); b.HasKey("ID");
@ -209,31 +209,31 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
modelBuilder.Entity("Kyoo.Models.MetadataID", b => modelBuilder.Entity("Kyoo.Models.MetadataID", b =>
{ {
b.Property<long>("ID") b.Property<int>("ID")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("bigint") .HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("DataID") b.Property<string>("DataID")
.HasColumnType("text"); .HasColumnType("text");
b.Property<long?>("EpisodeID") b.Property<int?>("EpisodeID")
.HasColumnType("bigint"); .HasColumnType("integer");
b.Property<string>("Link") b.Property<string>("Link")
.HasColumnType("text"); .HasColumnType("text");
b.Property<long?>("PeopleID") b.Property<int?>("PeopleID")
.HasColumnType("bigint"); .HasColumnType("integer");
b.Property<long>("ProviderID") b.Property<int>("ProviderID")
.HasColumnType("bigint"); .HasColumnType("integer");
b.Property<long?>("SeasonID") b.Property<int?>("SeasonID")
.HasColumnType("bigint"); .HasColumnType("integer");
b.Property<long?>("ShowID") b.Property<int?>("ShowID")
.HasColumnType("bigint"); .HasColumnType("integer");
b.HasKey("ID"); b.HasKey("ID");
@ -252,9 +252,9 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
modelBuilder.Entity("Kyoo.Models.People", b => modelBuilder.Entity("Kyoo.Models.People", b =>
{ {
b.Property<long>("ID") b.Property<int>("ID")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("bigint") .HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("ImgPrimary") b.Property<string>("ImgPrimary")
@ -276,19 +276,19 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
modelBuilder.Entity("Kyoo.Models.PeopleLink", b => modelBuilder.Entity("Kyoo.Models.PeopleLink", b =>
{ {
b.Property<long>("ID") b.Property<int>("ID")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("bigint") .HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<long>("PeopleID") b.Property<int>("PeopleID")
.HasColumnType("bigint"); .HasColumnType("integer");
b.Property<string>("Role") b.Property<string>("Role")
.HasColumnType("text"); .HasColumnType("text");
b.Property<long>("ShowID") b.Property<int>("ShowID")
.HasColumnType("bigint"); .HasColumnType("integer");
b.Property<string>("Type") b.Property<string>("Type")
.HasColumnType("text"); .HasColumnType("text");
@ -304,9 +304,9 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
modelBuilder.Entity("Kyoo.Models.ProviderID", b => modelBuilder.Entity("Kyoo.Models.ProviderID", b =>
{ {
b.Property<long>("ID") b.Property<int>("ID")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("bigint") .HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("Logo") b.Property<string>("Logo")
@ -325,16 +325,16 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
modelBuilder.Entity("Kyoo.Models.ProviderLink", b => modelBuilder.Entity("Kyoo.Models.ProviderLink", b =>
{ {
b.Property<long>("ID") b.Property<int>("ID")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("bigint") .HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<long?>("LibraryID") b.Property<int?>("LibraryID")
.HasColumnType("bigint"); .HasColumnType("integer");
b.Property<long>("ProviderID") b.Property<int>("ProviderID")
.HasColumnType("bigint"); .HasColumnType("integer");
b.HasKey("ID"); b.HasKey("ID");
@ -347,9 +347,9 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
modelBuilder.Entity("Kyoo.Models.Season", b => modelBuilder.Entity("Kyoo.Models.Season", b =>
{ {
b.Property<long>("ID") b.Property<int>("ID")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("bigint") .HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("ImgPrimary") b.Property<string>("ImgPrimary")
@ -358,17 +358,17 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
b.Property<string>("Overview") b.Property<string>("Overview")
.HasColumnType("text"); .HasColumnType("text");
b.Property<long>("SeasonNumber") b.Property<int>("SeasonNumber")
.HasColumnType("bigint"); .HasColumnType("integer");
b.Property<long>("ShowID") b.Property<int>("ShowID")
.HasColumnType("bigint"); .HasColumnType("integer");
b.Property<string>("Title") b.Property<string>("Title")
.HasColumnType("text"); .HasColumnType("text");
b.Property<long?>("Year") b.Property<int?>("Year")
.HasColumnType("bigint"); .HasColumnType("integer");
b.HasKey("ID"); b.HasKey("ID");
@ -379,9 +379,9 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
modelBuilder.Entity("Kyoo.Models.Show", b => modelBuilder.Entity("Kyoo.Models.Show", b =>
{ {
b.Property<long>("ID") b.Property<int>("ID")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("bigint") .HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("Aliases") b.Property<string>("Aliases")
@ -390,8 +390,8 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
b.Property<string>("Backdrop") b.Property<string>("Backdrop")
.HasColumnType("text"); .HasColumnType("text");
b.Property<long?>("EndYear") b.Property<int?>("EndYear")
.HasColumnType("bigint"); .HasColumnType("integer");
b.Property<bool>("IsMovie") b.Property<bool>("IsMovie")
.HasColumnType("boolean"); .HasColumnType("boolean");
@ -411,14 +411,14 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
b.Property<string>("Slug") b.Property<string>("Slug")
.HasColumnType("text"); .HasColumnType("text");
b.Property<long?>("StartYear") b.Property<int?>("StartYear")
.HasColumnType("bigint"); .HasColumnType("integer");
b.Property<int?>("Status") b.Property<int?>("Status")
.HasColumnType("integer"); .HasColumnType("integer");
b.Property<long?>("StudioID") b.Property<int?>("StudioID")
.HasColumnType("bigint"); .HasColumnType("integer");
b.Property<string>("Title") b.Property<string>("Title")
.HasColumnType("text"); .HasColumnType("text");
@ -438,9 +438,9 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
modelBuilder.Entity("Kyoo.Models.Studio", b => modelBuilder.Entity("Kyoo.Models.Studio", b =>
{ {
b.Property<long>("ID") b.Property<int>("ID")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("bigint") .HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("Name") b.Property<string>("Name")
@ -459,16 +459,16 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
modelBuilder.Entity("Kyoo.Models.Track", b => modelBuilder.Entity("Kyoo.Models.Track", b =>
{ {
b.Property<long>("ID") b.Property<int>("ID")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("bigint") .HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("Codec") b.Property<string>("Codec")
.HasColumnType("text"); .HasColumnType("text");
b.Property<long>("EpisodeID") b.Property<int>("EpisodeID")
.HasColumnType("bigint"); .HasColumnType("integer");
b.Property<bool>("IsDefault") b.Property<bool>("IsDefault")
.HasColumnType("boolean"); .HasColumnType("boolean");

View File

@ -137,6 +137,18 @@ namespace Kyoo
AllowedOrigins = { new Uri(publicUrl).GetLeftPart(UriPartial.Authority) } 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.AddScoped<ILibraryManager, LibraryManager>();
services.AddSingleton<ITranscoder, Transcoder>(); services.AddSingleton<ITranscoder, Transcoder>();
services.AddSingleton<IThumbnailsManager, ThumbnailsManager>(); services.AddSingleton<IThumbnailsManager, ThumbnailsManager>();

View File

@ -8,7 +8,6 @@ using System.Text.RegularExpressions;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Kyoo.Models.Watch; using Kyoo.Models.Watch;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
namespace Kyoo.Controllers namespace Kyoo.Controllers
@ -28,11 +27,11 @@ namespace Kyoo.Controllers
private ITranscoder _transcoder; private ITranscoder _transcoder;
private IConfiguration _config; private IConfiguration _config;
public IEnumerable<string> GetPossibleParameters() public async Task<IEnumerable<string>> GetPossibleParameters()
{ {
using IServiceScope serviceScope = _serviceProvider.CreateScope(); using IServiceScope serviceScope = _serviceProvider.CreateScope();
ILibraryManager libraryManager = serviceScope.ServiceProvider.GetService<ILibraryManager>(); ILibraryManager libraryManager = serviceScope.ServiceProvider.GetService<ILibraryManager>();
return libraryManager.GetLibraries().Select(x => x.Slug); return (await libraryManager.GetLibraries()).Select(x => x.Slug);
} }
public int? Progress() public int? Progress()
@ -53,28 +52,27 @@ namespace Kyoo.Controllers
{ {
using IServiceScope serviceScope = _serviceProvider.CreateScope(); using IServiceScope serviceScope = _serviceProvider.CreateScope();
ILibraryManager libraryManager = serviceScope.ServiceProvider.GetService<ILibraryManager>(); ILibraryManager libraryManager = serviceScope.ServiceProvider.GetService<ILibraryManager>();
IEnumerable<Episode> episodes = libraryManager.GetEpisodes(); ICollection<Episode> episodes = await libraryManager.GetEpisodes();
IEnumerable<Library> libraries = argument == null ICollection<Library> libraries = argument == null
? libraryManager.GetLibraries() ? await libraryManager.GetLibraries()
: new [] {libraryManager.GetLibrary(argument)}; : new [] { await libraryManager.GetLibrary(argument)};
foreach (Episode episode in episodes) foreach (Episode episode in episodes)
{ {
if (!File.Exists(episode.Path)) 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) 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!"); 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)}."); Console.WriteLine($"Scanning library {library.Name} at {string.Join(", ", library.Paths)}.");
return Task.WhenAll(library.Paths.Select(async path => return Task.WhenAll(library.Paths.Select(async path =>
@ -89,29 +87,29 @@ namespace Kyoo.Controllers
} }
catch (DirectoryNotFoundException) 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; return Task.CompletedTask;
} }
catch (PathTooLongException) 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; return Task.CompletedTask;
} }
catch (ArgumentException) 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; return Task.CompletedTask;
} }
catch (UnauthorizedAccessException) 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.CompletedTask;
} }
// return Task.WhenAll(files.Select(file => // return Task.WhenAll(files.Select(file =>
foreach (string file in files) 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; continue; //return Task.CompletedTask;
string relativePath = file.Substring(path.Length); string relativePath = file.Substring(path.Length);
/*return*/ await RegisterFile(file, relativePath, library, cancellationToken); /*return*/ await RegisterFile(file, relativePath, library, cancellationToken);
@ -128,7 +126,6 @@ namespace Kyoo.Controllers
using IServiceScope serviceScope = _serviceProvider.CreateScope(); using IServiceScope serviceScope = _serviceProvider.CreateScope();
ILibraryManager libraryManager = serviceScope.ServiceProvider.GetService<ILibraryManager>(); ILibraryManager libraryManager = serviceScope.ServiceProvider.GetService<ILibraryManager>();
((DbSet<Library>)libraryManager.GetLibraries()).Attach(library);
string patern = _config.GetValue<string>("regex"); string patern = _config.GetValue<string>("regex");
Regex regex = new Regex(patern, RegexOptions.IgnoreCase); Regex regex = new Regex(patern, RegexOptions.IgnoreCase);
@ -137,74 +134,97 @@ namespace Kyoo.Controllers
string showPath = Path.GetDirectoryName(path); string showPath = Path.GetDirectoryName(path);
string collectionName = match.Groups["Collection"]?.Value; string collectionName = match.Groups["Collection"]?.Value;
string showName = match.Groups["ShowTitle"].Value; string showName = match.Groups["ShowTitle"].Value;
long seasonNumber = long.TryParse(match.Groups["Season"].Value, out long tmp) ? tmp : -1; int seasonNumber = int.TryParse(match.Groups["Season"].Value, out int tmp) ? tmp : -1;
long episodeNumber = long.TryParse(match.Groups["Episode"].Value, out tmp) ? tmp : -1; int episodeNumber = int.TryParse(match.Groups["Episode"].Value, out tmp) ? tmp : -1;
long absoluteNumber = long.TryParse(match.Groups["Absolute"].Value, out tmp) ? tmp : -1; int absoluteNumber = int.TryParse(match.Groups["Absolute"].Value, out tmp) ? tmp : -1;
Collection collection = await GetCollection(libraryManager, collectionName, library); Collection collection = await GetCollection(libraryManager, collectionName, library);
bool isMovie = seasonNumber == -1 && episodeNumber == -1 && absoluteNumber == -1; bool isMovie = seasonNumber == -1 && episodeNumber == -1 && absoluteNumber == -1;
Show show = await GetShow(libraryManager, showName, showPath, isMovie, library); Show show = await GetShow(libraryManager, showName, showPath, isMovie, library);
if (isMovie) if (isMovie)
libraryManager.Register(await GetMovie(show, path)); await libraryManager.RegisterEpisode(await GetMovie(show, path));
else else
{ {
Season season = await GetSeason(libraryManager, show, seasonNumber, library); Season season = await GetSeason(libraryManager, show, seasonNumber, library);
Episode episode = await GetEpisode(libraryManager, show, season, episodeNumber, absoluteNumber, path, 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); await libraryManager.AddShowLink(show, library, collection);
libraryManager.RegisterShowLinks(library, collection, show); Console.WriteLine($"Episode at {path} registered.");
Console.WriteLine($"Registering episode at: {path}");
await libraryManager.SaveChanges();
} }
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)) if (string.IsNullOrEmpty(collectionName))
return await Task.FromResult<Collection>(null); return null;
Collection name = libraryManager.GetCollection(Utility.ToSlug(collectionName)); Collection collection = await libraryManager.GetCollection(Utility.ToSlug(collectionName));
if (name != null) if (collection != null)
return name; return collection;
return await _metadataProvider.GetCollectionFromName(collectionName, library); 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) if (show != null)
return show; return show;
show = await _metadataProvider.SearchShow(showTitle, isMovie, library); show = await _metadataProvider.SearchShow(showTitle, isMovie, library);
show.Path = showPath; show.Path = showPath;
show.People = await _metadataProvider.GetPeople(show, library); show.People = await _metadataProvider.GetPeople(show, library);
await libraryManager.RegisterShow(show);
await _thumbnailsManager.Validate(show.People); await _thumbnailsManager.Validate(show.People);
await _thumbnailsManager.Validate(show); await _thumbnailsManager.Validate(show);
return 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) if (seasonNumber == -1)
return default; return default;
Season season = libraryManager.GetSeason(show.Slug, seasonNumber); Season season = await libraryManager.GetSeason(show.Slug, seasonNumber);
if (season == null) if (season == null)
{ {
season = await _metadataProvider.GetSeason(show, seasonNumber, library); season = await _metadataProvider.GetSeason(show, seasonNumber, library);
await libraryManager.RegisterSeason(season);
await _thumbnailsManager.Validate(season); await _thumbnailsManager.Validate(season);
} }
season.Show = show; season.Show = show;
return season; 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); Episode episode = await _metadataProvider.GetEpisode(show,
if (season == null) episodePath,
season = await GetSeason(libraryManager, show, episode.SeasonNumber, library); season?.SeasonNumber ?? -1,
episodeNumber,
absoluteNumber,
library);
season ??= await GetSeason(libraryManager, show, episode.SeasonNumber, library);
episode.Season = season; episode.Season = season;
episode.SeasonID = season?.ID;
if (season == null) 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; return default;
} }
@ -215,7 +235,13 @@ namespace Kyoo.Controllers
private async Task<Episode> GetMovie(Show show, string episodePath) 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); episode.Tracks = await GetTracks(episode);
return episode; return episode;
} }

View File

@ -58,9 +58,9 @@ namespace Kyoo.Tasks
return Task.CompletedTask; return Task.CompletedTask;
} }
public IEnumerable<string> GetPossibleParameters() public Task<IEnumerable<string>> GetPossibleParameters()
{ {
return null; return Task.FromResult<IEnumerable<string>>(null);
} }
public int? Progress() public int? Progress()

View File

@ -28,9 +28,9 @@ namespace Kyoo.Tasks
return Task.CompletedTask; return Task.CompletedTask;
} }
public IEnumerable<string> GetPossibleParameters() public Task<IEnumerable<string>> GetPossibleParameters()
{ {
return null; return Task.FromResult<IEnumerable<string>>(null);
} }
public int? Progress() public int? Progress()

View File

@ -24,9 +24,9 @@ namespace Kyoo.Tasks
return Task.CompletedTask; return Task.CompletedTask;
} }
public IEnumerable<string> GetPossibleParameters() public Task<IEnumerable<string>> GetPossibleParameters()
{ {
return null; return Task.FromResult<IEnumerable<string>>(null);
} }
public int? Progress() public int? Progress()

View File

@ -62,7 +62,7 @@ namespace Kyoo.Tasks
edited.ID = old.ID; edited.ID = old.ID;
edited.Slug = old.Slug; edited.Slug = old.Slug;
edited.Path = old.Path; edited.Path = old.Path;
await libraryManager.Edit(edited, true); await libraryManager.EditShow(edited, true);
await _thumbnailsManager.Validate(edited, true); await _thumbnailsManager.Validate(edited, true);
} }
if (old.Seasons != null) if (old.Seasons != null)
@ -95,7 +95,7 @@ namespace Kyoo.Tasks
Library library = _database.LibraryLinks.First(x => x.Show == show && x.Library != null).Library; Library library = _database.LibraryLinks.First(x => x.Show == show && x.Library != null).Library;
Season edited = await _providerManager.GetSeason(show, old.SeasonNumber, library); Season edited = await _providerManager.GetSeason(show, old.SeasonNumber, library);
edited.ID = old.ID; edited.ID = old.ID;
await libraryManager.Edit(edited, true); await libraryManager.EditSeason(edited, true);
await _thumbnailsManager.Validate(edited, true); await _thumbnailsManager.Validate(edited, true);
} }
if (old.Episodes != null) if (old.Episodes != null)
@ -110,13 +110,13 @@ namespace Kyoo.Tasks
Library library = _database.LibraryLinks.First(x => x.Show == show && x.Library != null).Library; 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); Episode edited = await _providerManager.GetEpisode(show, old.Path, old.SeasonNumber, old.EpisodeNumber, old.AbsoluteNumber, library);
edited.ID = old.ID; edited.ID = old.ID;
await libraryManager.Edit(edited, true); await libraryManager.EditEpisode(edited, true);
await _thumbnailsManager.Validate(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() public int? Progress()

View File

@ -2,6 +2,7 @@
using Kyoo.Models; using Kyoo.Models;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
namespace Kyoo.Api namespace Kyoo.Api
@ -19,9 +20,9 @@ namespace Kyoo.Api
[HttpGet("{collectionSlug}")] [HttpGet("{collectionSlug}")]
[Authorize(Policy="Read")] [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) if (collection == null)
return NotFound(); return NotFound();

View File

@ -2,6 +2,7 @@
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
using Kyoo.Controllers; using Kyoo.Controllers;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
@ -20,9 +21,9 @@ namespace Kyoo.Api
[HttpGet("{showSlug}/season/{seasonNumber}")] [HttpGet("{showSlug}/season/{seasonNumber}")]
[Authorize(Policy="Read")] [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) if(episodes == null)
return NotFound(); return NotFound();
@ -33,9 +34,9 @@ namespace Kyoo.Api
[HttpGet("{showSlug}/season/{seasonNumber}/episode/{episodeNumber}")] [HttpGet("{showSlug}/season/{seasonNumber}/episode/{episodeNumber}")]
[Authorize(Policy="Read")] [Authorize(Policy="Read")]
[JsonDetailed] [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) if (episode == null)
return NotFound(); return NotFound();

View File

@ -1,5 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
using Kyoo.Controllers; using Kyoo.Controllers;
using Kyoo.Models; using Kyoo.Models;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
@ -18,9 +19,9 @@ namespace Kyoo.API
_libraryManager = libraryManager; _libraryManager = libraryManager;
} }
public ActionResult<IEnumerable<Genre>> Index() public async Task<ActionResult<IEnumerable<Genre>>> Index()
{ {
return _libraryManager.GetGenres().ToList(); return (await _libraryManager.GetGenres()).ToList();
} }
} }
} }

View File

@ -3,6 +3,7 @@ using Kyoo.Models;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
namespace Kyoo.Api namespace Kyoo.Api
@ -22,15 +23,15 @@ namespace Kyoo.Api
} }
[HttpGet] [HttpGet]
public IEnumerable<Library> GetLibraries() public async Task<IEnumerable<Library>> GetLibraries()
{ {
return _libraryManager.GetLibraries(); return await _libraryManager.GetLibraries();
} }
[Route("/api/library/create")] [Route("/api/library/create")]
[HttpPost] [HttpPost]
[Authorize(Policy="Admin")] [Authorize(Policy="Admin")]
public IActionResult CreateLibrary([FromBody] Library library) public async Task<IActionResult> CreateLibrary([FromBody] Library library)
{ {
if (!ModelState.IsValid) if (!ModelState.IsValid)
return BadRequest(library); return BadRequest(library);
@ -40,19 +41,18 @@ namespace Kyoo.Api
return BadRequest(new {error = "The library's name must be set and not empty"}); return BadRequest(new {error = "The library's name must be set and not empty"});
if (library.Paths == null || !library.Paths.Any()) if (library.Paths == null || !library.Paths.Any())
return BadRequest(new {error = "The library should have a least one path."}); 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"}); return BadRequest(new {error = "Duplicated library slug"});
_libraryManager.Register(library); await _libraryManager.RegisterLibrary(library);
_libraryManager.SaveChanges();
_taskManager.StartTask("scan", library.Slug); _taskManager.StartTask("scan", library.Slug);
return Ok(); return Ok();
} }
[HttpGet("{librarySlug}")] [HttpGet("{librarySlug}")]
[Authorize(Policy="Read")] [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) if (library == null)
return NotFound(); return NotFound();

View File

@ -1,4 +1,5 @@
using System.Linq; using System.Linq;
using System.Threading.Tasks;
using Kyoo.Controllers; using Kyoo.Controllers;
using Kyoo.Models; using Kyoo.Models;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
@ -19,9 +20,9 @@ namespace Kyoo.Api
[HttpGet("{peopleSlug}")] [HttpGet("{peopleSlug}")]
[Authorize(Policy="Read")] [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) if (people == null)
return NotFound(); return NotFound();

View File

@ -1,4 +1,5 @@
using Kyoo.Controllers; using System.Threading.Tasks;
using Kyoo.Controllers;
using Kyoo.Models; using Kyoo.Models;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
@ -18,17 +19,17 @@ namespace Kyoo.Api
[HttpGet("{query}")] [HttpGet("{query}")]
[Authorize(Policy="Read")] [Authorize(Policy="Read")]
public ActionResult<SearchResult> Search(string query) public async Task<ActionResult<SearchResult>> Search(string query)
{ {
SearchResult result = new SearchResult SearchResult result = new SearchResult
{ {
Query = query, Query = query,
Collections = _libraryManager.SearchCollections(query), Collections = await _libraryManager.SearchCollections(query),
Shows = _libraryManager.SearchShows(query), Shows = await _libraryManager.SearchShows(query),
Episodes = _libraryManager.SearchEpisodes(query), Episodes = await _libraryManager.SearchEpisodes(query),
People = _libraryManager.SearchPeople(query), People = await _libraryManager.SearchPeople(query),
Genres = _libraryManager.SearchGenres(query), Genres = await _libraryManager.SearchGenres(query),
Studios = _libraryManager.SearchStudios(query) Studios = await _libraryManager.SearchStudios(query)
}; };
return result; return result;
} }

View File

@ -37,15 +37,18 @@ namespace Kyoo.Api
[Authorize(Policy="Read")] [Authorize(Policy="Read")]
public IEnumerable<Show> GetShows() 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}")] [HttpGet("{slug}")]
[Authorize(Policy="Read")] [Authorize(Policy="Read")]
[JsonDetailed] [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) if (show == null)
return NotFound(); return NotFound();
@ -55,7 +58,7 @@ namespace Kyoo.Api
[HttpPost("edit/{slug}")] [HttpPost("edit/{slug}")]
[Authorize(Policy="Write")] [Authorize(Policy="Write")]
public IActionResult EditShow(string slug, [FromBody] Show show) public async Task<IActionResult> EditShow(string slug, [FromBody] Show show)
{ {
if (!ModelState.IsValid) if (!ModelState.IsValid)
return BadRequest(show); return BadRequest(show);
@ -66,7 +69,7 @@ namespace Kyoo.Api
show.ID = old.ID; show.ID = old.ID;
show.Slug = slug; show.Slug = slug;
show.Path = old.Path; show.Path = old.Path;
_libraryManager.Edit(show, false); await _libraryManager.EditShow(show, false);
return Ok(); return Ok();
} }
@ -79,7 +82,6 @@ namespace Kyoo.Api
Show show = _database.Shows.Include(x => x.ExternalIDs).FirstOrDefault(x => x.Slug == slug); Show show = _database.Shows.Include(x => x.ExternalIDs).FirstOrDefault(x => x.Slug == slug);
if (show == null) if (show == null)
return NotFound(); return NotFound();
show.ExternalIDs = _libraryManager.Validate(externalIDs);
_database.SaveChanges(); _database.SaveChanges();
_taskManager.StartTask("re-scan", $"show/{slug}"); _taskManager.StartTask("re-scan", $"show/{slug}");
return Ok(); return Ok();
@ -96,7 +98,7 @@ namespace Kyoo.Api
[Authorize(Policy = "Write")] [Authorize(Policy = "Write")]
public async Task<IActionResult> DownloadImages(string slug) public async Task<IActionResult> DownloadImages(string slug)
{ {
Show show = _libraryManager.GetShow(slug); Show show = await _libraryManager.GetShow(slug);
if (show == null) if (show == null)
return NotFound(); return NotFound();
await _thumbnailsManager.Validate(show, true); await _thumbnailsManager.Validate(show, true);

View File

@ -1,5 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
using Kyoo.Controllers; using Kyoo.Controllers;
using Kyoo.Models; using Kyoo.Models;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
@ -18,9 +19,9 @@ namespace Kyoo.API
_libraryManager = libraryManager; _libraryManager = libraryManager;
} }
public ActionResult<IEnumerable<Studio>> Index() public async Task<ActionResult<IEnumerable<Studio>>> Index()
{ {
return _libraryManager.GetStudios().ToList(); return (await _libraryManager.GetStudios()).ToList();
} }
} }
} }

View File

@ -14,31 +14,37 @@ namespace Kyoo.Api
public class SubtitleController : ControllerBase public class SubtitleController : ControllerBase
{ {
private readonly ILibraryManager _libraryManager; 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; _libraryManager = libraryManager;
_transcoder = transcoder; // _transcoder = transcoder;
} }
[HttpGet("{showSlug}-s{seasonNumber:int}e{episodeNumber:int}.{identifier}.{extension?}")] [HttpGet("{showSlug}-s{seasonNumber:int}e{episodeNumber:int}.{identifier}.{extension?}")]
[Authorize(Policy="Play")] [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; string languageTag = identifier.Length == 3 ? identifier.Substring(0, 3) : null;
bool forced = identifier.Length > 4 && identifier.Substring(4) == "forced"; bool forced = identifier.Length > 4 && identifier.Substring(4) == "forced";
Track subtitle = null; Track subtitle = null;
if (languageTag != 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); .FirstOrDefault(x => x.Language == languageTag && x.IsForced == forced);
if (subtitle == null) if (subtitle == null)
{ {
string idString = identifier.IndexOf('-') != -1 ? identifier.Substring(0, identifier.IndexOf('-')) : identifier; string idString = identifier.IndexOf('-') != -1
long.TryParse(idString, out long id); ? identifier.Substring(0, identifier.IndexOf('-'))
subtitle = _libraryManager.GetTracks().FirstOrDefault(x => x.ID == id); : identifier;
int.TryParse(idString, out int id);
subtitle = await _libraryManager.GetTrack(id);
} }
if (subtitle == null) if (subtitle == null)
@ -57,43 +63,43 @@ namespace Kyoo.Api
return PhysicalFile(subtitle.Path, mime); return PhysicalFile(subtitle.Path, mime);
} }
[HttpGet("extract/{showSlug}-s{seasonNumber}e{episodeNumber}")] // [HttpGet("extract/{showSlug}-s{seasonNumber}e{episodeNumber}")]
[Authorize(Policy="Admin")] // [Authorize(Policy="Admin")]
public async Task<string> ExtractSubtitle(string showSlug, long seasonNumber, long episodeNumber) // public async Task<string> ExtractSubtitle(string showSlug, long seasonNumber, long episodeNumber)
{ // {
Episode episode = _libraryManager.GetEpisode(showSlug, seasonNumber, episodeNumber); // Episode episode = _libraryManager.GetEpisode(showSlug, seasonNumber, episodeNumber);
episode.Tracks = null; // episode.Tracks = null;
//
Track[] tracks = await _transcoder.ExtractSubtitles(episode.Path); // Track[] tracks = await _transcoder.ExtractSubtitles(episode.Path);
foreach (Track track in tracks) // foreach (Track track in tracks)
{ // {
track.EpisodeID = episode.ID; // track.EpisodeID = episode.ID;
_libraryManager.Register(track); // _libraryManager.Register(track);
} // }
await _libraryManager.SaveChanges(); // await _libraryManager.SaveChanges();
return "Done. " + tracks.Length + " track(s) extracted."; // return "Done. " + tracks.Length + " track(s) extracted.";
} // }
//
[HttpGet("extract/{showSlug}")] // [HttpGet("extract/{showSlug}")]
[Authorize(Policy="Admin")] // [Authorize(Policy="Admin")]
public async Task<string> ExtractSubtitle(string showSlug) // public async Task<string> ExtractSubtitle(string showSlug)
{ // {
IEnumerable<Episode> episodes = _libraryManager.GetShow(showSlug).Episodes; // IEnumerable<Episode> episodes = _libraryManager.GetShow(showSlug).Episodes;
foreach (Episode episode in episodes) // foreach (Episode episode in episodes)
{ // {
episode.Tracks = null; // episode.Tracks = null;
//
Track[] tracks = await _transcoder.ExtractSubtitles(episode.Path); // Track[] tracks = await _transcoder.ExtractSubtitles(episode.Path);
foreach (Track track in tracks) // foreach (Track track in tracks)
{ // {
track.EpisodeID = episode.ID; // track.EpisodeID = episode.ID;
_libraryManager.Register(track); // _libraryManager.Register(track);
} // }
await _libraryManager.SaveChanges(); // await _libraryManager.SaveChanges();
} // }
//
return "Done."; // return "Done.";
} // }
} }

View File

@ -1,6 +1,7 @@
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using System.IO; using System.IO;
using System.Threading.Tasks;
using Kyoo.Controllers; using Kyoo.Controllers;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
@ -20,9 +21,9 @@ namespace Kyoo.Api
[HttpGet("poster/{showSlug}")] [HttpGet("poster/{showSlug}")]
[Authorize(Policy="Read")] [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) if (path == null)
return NotFound(); return NotFound();
@ -35,9 +36,9 @@ namespace Kyoo.Api
[HttpGet("logo/{showSlug}")] [HttpGet("logo/{showSlug}")]
[Authorize(Policy="Read")] [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) if (path == null)
return NotFound(); return NotFound();
@ -50,9 +51,9 @@ namespace Kyoo.Api
[HttpGet("backdrop/{showSlug}")] [HttpGet("backdrop/{showSlug}")]
[Authorize(Policy="Read")] [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) if (path == null)
return NotFound(); return NotFound();
@ -76,9 +77,9 @@ namespace Kyoo.Api
[HttpGet("thumb/{showSlug}-s{seasonNumber}e{episodeNumber}")] [HttpGet("thumb/{showSlug}-s{seasonNumber}e{episodeNumber}")]
[Authorize(Policy="Read")] [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) if (path == null)
return NotFound(); return NotFound();

View File

@ -27,9 +27,9 @@ namespace Kyoo.Api
[HttpGet("{showSlug}-s{seasonNumber}e{episodeNumber}")] [HttpGet("{showSlug}-s{seasonNumber}e{episodeNumber}")]
[Authorize(Policy="Play")] [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)) if (episode != null && System.IO.File.Exists(episode.Path))
return PhysicalFile(episode.Path, "video/x-matroska", true); return PhysicalFile(episode.Path, "video/x-matroska", true);
@ -38,9 +38,9 @@ namespace Kyoo.Api
[HttpGet("transmux/{showSlug}-s{seasonNumber}e{episodeNumber}")] [HttpGet("transmux/{showSlug}-s{seasonNumber}e{episodeNumber}")]
[Authorize(Policy="Play")] [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)) if (episode == null || !System.IO.File.Exists(episode.Path))
return NotFound(); return NotFound();
@ -61,9 +61,9 @@ namespace Kyoo.Api
[HttpGet("transcode/{showSlug}-s{seasonNumber}e{episodeNumber}")] [HttpGet("transcode/{showSlug}-s{seasonNumber}e{episodeNumber}")]
[Authorize(Policy="Play")] [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)) if (episode == null || !System.IO.File.Exists(episode.Path))
return NotFound(); return NotFound();
@ -85,9 +85,9 @@ namespace Kyoo.Api
[HttpGet("{movieSlug}")] [HttpGet("{movieSlug}")]
[Authorize(Policy="Play")] [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)) if (episode != null && System.IO.File.Exists(episode.Path))
return PhysicalFile(episode.Path, "video/webm", true); return PhysicalFile(episode.Path, "video/webm", true);
@ -98,7 +98,7 @@ namespace Kyoo.Api
[Authorize(Policy="Play")] [Authorize(Policy="Play")]
public async Task<IActionResult> Transmux(string movieSlug) 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)) if (episode == null || !System.IO.File.Exists(episode.Path))
return NotFound(); return NotFound();
@ -112,7 +112,7 @@ namespace Kyoo.Api
[Authorize(Policy="Play")] [Authorize(Policy="Play")]
public async Task<IActionResult> Transcode(string movieSlug) 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)) if (episode == null || !System.IO.File.Exists(episode.Path))
return NotFound(); return NotFound();

View File

@ -1,4 +1,5 @@
using Kyoo.Controllers; using System.Threading.Tasks;
using Kyoo.Controllers;
using Kyoo.Models; using Kyoo.Models;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
@ -18,9 +19,9 @@ namespace Kyoo.Api
[HttpGet("{showSlug}-s{seasonNumber}e{episodeNumber}")] [HttpGet("{showSlug}-s{seasonNumber}e{episodeNumber}")]
[Authorize(Policy="Read")] [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) if(item == null)
return NotFound(); return NotFound();
@ -30,9 +31,9 @@ namespace Kyoo.Api
[HttpGet("{movieSlug}")] [HttpGet("{movieSlug}")]
[Authorize(Policy="Read")] [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) if(item == null)
return NotFound(); return NotFound();