mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-24 02:02:36 -04:00
Starting to rework models
This commit is contained in:
parent
00ef372767
commit
8f6578dfb9
@ -66,6 +66,11 @@ namespace Kyoo.Controllers
|
||||
_ => throw new ArgumentException($"The sort order, if set, should be :asc or :desc but it was :{order}.")
|
||||
};
|
||||
}
|
||||
|
||||
public Sort<TValue> To<TValue>()
|
||||
{
|
||||
return new Sort<TValue>(Key.Convert<Func<TValue, object>>(), Descendant);
|
||||
}
|
||||
}
|
||||
|
||||
public interface IRepository<T> : IDisposable, IAsyncDisposable where T : IResource
|
||||
|
@ -6,7 +6,10 @@ namespace Kyoo.Models.Exceptions
|
||||
{
|
||||
public override string Message { get; }
|
||||
|
||||
public DuplicatedItemException() {}
|
||||
public DuplicatedItemException()
|
||||
{
|
||||
Message = "Already exists in the databse.";
|
||||
}
|
||||
|
||||
public DuplicatedItemException(string message)
|
||||
{
|
||||
|
@ -1,31 +1,17 @@
|
||||
using Newtonsoft.Json;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Kyoo.Models.Attributes;
|
||||
|
||||
namespace Kyoo.Models
|
||||
{
|
||||
public class Collection : IResource
|
||||
{
|
||||
[JsonIgnore] public int ID { get; set; }
|
||||
public int ID { get; set; }
|
||||
public string Slug { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Poster { get; set; }
|
||||
public string Overview { get; set; }
|
||||
[NotMergable] [JsonIgnore] public virtual IEnumerable<CollectionLink> Links { get; set; }
|
||||
[JsonIgnore] public virtual IEnumerable<Show> Shows
|
||||
{
|
||||
get => Links.Select(x => x.Show);
|
||||
set => Links = value.Select(x => new CollectionLink(this, x));
|
||||
}
|
||||
|
||||
[NotMergable] [JsonIgnore] public virtual IEnumerable<LibraryLink> LibraryLinks { get; set; }
|
||||
|
||||
[NotMergable] [JsonIgnore] public IEnumerable<Library> Libraries
|
||||
{
|
||||
get => LibraryLinks?.Select(x => x.Library);
|
||||
set => LibraryLinks = value?.Select(x => new LibraryLink(x, this));
|
||||
}
|
||||
[JsonIgnore] public virtual IEnumerable<Show> Shows { get; set; }
|
||||
[JsonIgnore] public virtual IEnumerable<Library> Libraries { get; set; }
|
||||
|
||||
public Collection() { }
|
||||
|
||||
|
@ -7,10 +7,10 @@ namespace Kyoo.Models
|
||||
{
|
||||
public class Episode : IResource, IOnMerge
|
||||
{
|
||||
[JsonIgnore] public int ID { get; set; }
|
||||
[JsonIgnore] public int ShowID { get; set; }
|
||||
public int ID { get; set; }
|
||||
public int ShowID { get; set; }
|
||||
[JsonIgnore] public virtual Show Show { get; set; }
|
||||
[JsonIgnore] public int? SeasonID { get; set; }
|
||||
public int? SeasonID { get; set; }
|
||||
[JsonIgnore] public virtual Season Season { get; set; }
|
||||
|
||||
public int SeasonNumber { get; set; } = -1;
|
||||
@ -23,12 +23,12 @@ namespace Kyoo.Models
|
||||
|
||||
public int Runtime { get; set; } //This runtime variable should be in minutes
|
||||
|
||||
[JsonIgnore] public string ImgPrimary { get; set; }
|
||||
[JsonIgnore] public string Poster { get; set; }
|
||||
public virtual IEnumerable<MetadataID> ExternalIDs { get; set; }
|
||||
|
||||
[JsonIgnore] public virtual IEnumerable<Track> Tracks { get; set; }
|
||||
|
||||
public string ShowTitle => Show.Title; // Used in the API response only
|
||||
public string ShowTitle => Show.Title;
|
||||
public string Slug => GetSlug(Show.Slug, SeasonNumber, EpisodeNumber);
|
||||
public string Thumb
|
||||
{
|
||||
@ -36,7 +36,7 @@ namespace Kyoo.Models
|
||||
{
|
||||
if (Show != null)
|
||||
return "thumb/" + Slug;
|
||||
return ImgPrimary;
|
||||
return Poster;
|
||||
}
|
||||
}
|
||||
|
||||
@ -50,7 +50,7 @@ namespace Kyoo.Models
|
||||
string overview,
|
||||
DateTime? releaseDate,
|
||||
int runtime,
|
||||
string imgPrimary,
|
||||
string poster,
|
||||
IEnumerable<MetadataID> externalIDs)
|
||||
{
|
||||
SeasonNumber = seasonNumber;
|
||||
@ -60,7 +60,7 @@ namespace Kyoo.Models
|
||||
Overview = overview;
|
||||
ReleaseDate = releaseDate;
|
||||
Runtime = runtime;
|
||||
ImgPrimary = imgPrimary;
|
||||
Poster = poster;
|
||||
ExternalIDs = externalIDs;
|
||||
}
|
||||
|
||||
@ -74,7 +74,7 @@ namespace Kyoo.Models
|
||||
string overview,
|
||||
DateTime? releaseDate,
|
||||
int runtime,
|
||||
string imgPrimary,
|
||||
string poster,
|
||||
IEnumerable<MetadataID> externalIDs)
|
||||
{
|
||||
ShowID = showID;
|
||||
@ -87,7 +87,7 @@ namespace Kyoo.Models
|
||||
Overview = overview;
|
||||
ReleaseDate = releaseDate;
|
||||
Runtime = runtime;
|
||||
ImgPrimary = imgPrimary;
|
||||
Poster = poster;
|
||||
ExternalIDs = externalIDs;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Kyoo.Models.Attributes;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Kyoo.Models
|
||||
@ -11,13 +9,7 @@ namespace Kyoo.Models
|
||||
public string Slug { get; set; }
|
||||
public string Name { get; set; }
|
||||
|
||||
[NotMergable] [JsonIgnore] public virtual IEnumerable<GenreLink> Links { get; set; }
|
||||
|
||||
[NotMergable] [JsonIgnore] public IEnumerable<Show> Shows
|
||||
{
|
||||
get => Links.Select(x => x.Show);
|
||||
set => Links = value?.Select(x => new GenreLink(x, this));
|
||||
}
|
||||
[JsonIgnore] public virtual IEnumerable<Show> Shows { get; set; }
|
||||
|
||||
public Genre() {}
|
||||
|
||||
|
@ -1,6 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Kyoo.Models.Attributes;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Kyoo.Models
|
||||
@ -12,28 +10,10 @@ namespace Kyoo.Models
|
||||
public string Name { get; set; }
|
||||
public IEnumerable<string> Paths { get; set; }
|
||||
|
||||
public IEnumerable<ProviderID> Providers
|
||||
{
|
||||
get => ProviderLinks?.Select(x => x.Provider);
|
||||
set => ProviderLinks = value.Select(x => new ProviderLink(x, this)).ToList();
|
||||
}
|
||||
[NotMergable] [JsonIgnore] public virtual IEnumerable<ProviderLink> ProviderLinks { get; set; }
|
||||
[NotMergable] [JsonIgnore] public virtual IEnumerable<LibraryLink> Links { get; set; }
|
||||
public virtual IEnumerable<ProviderID> Providers { get; set; }
|
||||
|
||||
[JsonIgnore] public IEnumerable<Show> Shows
|
||||
{
|
||||
get => Links?.Where(x => x.Show != null).Select(x => x.Show);
|
||||
set => Links = Utility.MergeLists(
|
||||
value?.Select(x => new LibraryLink(this, x)),
|
||||
Links?.Where(x => x.Show == null));
|
||||
}
|
||||
[JsonIgnore] public IEnumerable<Collection> Collections
|
||||
{
|
||||
get => Links?.Where(x => x.Collection != null).Select(x => x.Collection);
|
||||
set => Links = Utility.MergeLists(
|
||||
value?.Select(x => new LibraryLink(this, x)),
|
||||
Links?.Where(x => x.Collection == null));
|
||||
}
|
||||
[JsonIgnore] public virtual IEnumerable<Show> Shows { get; set; }
|
||||
[JsonIgnore] public virtual IEnumerable<Collection> Collections { get; set; }
|
||||
|
||||
public Library() { }
|
||||
|
||||
|
@ -7,8 +7,7 @@ namespace Kyoo.Models
|
||||
{
|
||||
public class Show : IResource, IOnMerge
|
||||
{
|
||||
[JsonIgnore] public int ID { get; set; }
|
||||
|
||||
public int ID { get; set; }
|
||||
public string Slug { get; set; }
|
||||
public string Title { get; set; }
|
||||
public IEnumerable<string> Aliases { get; set; }
|
||||
@ -24,38 +23,19 @@ namespace Kyoo.Models
|
||||
public string Logo { get; set; }
|
||||
public string Backdrop { get; set; }
|
||||
|
||||
public virtual IEnumerable<MetadataID> ExternalIDs { get; set; }
|
||||
|
||||
public bool IsMovie { get; set; }
|
||||
|
||||
public virtual IEnumerable<MetadataID> ExternalIDs { get; set; }
|
||||
|
||||
|
||||
public virtual IEnumerable<Genre> Genres
|
||||
{
|
||||
get => GenreLinks?.Select(x => x.Genre);
|
||||
set => GenreLinks = value?.Select(x => new GenreLink(this, x)).ToList();
|
||||
}
|
||||
[NotMergable] [JsonIgnore] public virtual IEnumerable<GenreLink> GenreLinks { get; set; }
|
||||
[JsonIgnore] public int? StudioID { get; set; }
|
||||
public virtual Studio Studio { get; set; }
|
||||
[JsonIgnore] public virtual Studio Studio { get; set; }
|
||||
[JsonIgnore] public virtual IEnumerable<Genre> Genres { get; set; }
|
||||
[JsonIgnore] public virtual IEnumerable<PeopleRole> People { get; set; }
|
||||
[JsonIgnore] public virtual IEnumerable<Season> Seasons { get; set; }
|
||||
[JsonIgnore] public virtual IEnumerable<Episode> Episodes { get; set; }
|
||||
|
||||
[NotMergable] [JsonIgnore] public virtual IEnumerable<LibraryLink> LibraryLinks { get; set; }
|
||||
|
||||
[NotMergable] [JsonIgnore] public IEnumerable<Library> Libraries
|
||||
{
|
||||
get => LibraryLinks?.Select(x => x.Library);
|
||||
set => LibraryLinks = value?.Select(x => new LibraryLink(x, this));
|
||||
}
|
||||
|
||||
[NotMergable] [JsonIgnore] public virtual IEnumerable<CollectionLink> CollectionLinks { get; set; }
|
||||
|
||||
[NotMergable] [JsonIgnore] public IEnumerable<Collection> Collections
|
||||
{
|
||||
get => CollectionLinks?.Select(x => x.Collection);
|
||||
set => CollectionLinks = value?.Select(x => new CollectionLink(x, this));
|
||||
}
|
||||
[JsonIgnore] public virtual IEnumerable<Library> Libraries { get; set; }
|
||||
[JsonIgnore] public virtual IEnumerable<Collection> Collections { get; set; }
|
||||
|
||||
public Show() { }
|
||||
|
||||
@ -117,14 +97,11 @@ namespace Kyoo.Models
|
||||
return ExternalIDs?.FirstOrDefault(x => x.Provider.Name == provider)?.DataID;
|
||||
}
|
||||
|
||||
public void OnMerge(object merged)
|
||||
public virtual void OnMerge(object merged)
|
||||
{
|
||||
if (ExternalIDs != null)
|
||||
foreach (MetadataID id in ExternalIDs)
|
||||
id.Show = this;
|
||||
if (GenreLinks != null)
|
||||
foreach (GenreLink genre in GenreLinks)
|
||||
genre.Show = this;
|
||||
if (People != null)
|
||||
foreach (PeopleRole link in People)
|
||||
link.Show = this;
|
||||
|
@ -3,9 +3,11 @@ using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using JetBrains.Annotations;
|
||||
using Kyoo.Models;
|
||||
using Kyoo.Models.Attributes;
|
||||
@ -71,6 +73,21 @@ namespace Kyoo
|
||||
return list.Concat(second.Where(x => !list.Any(y => isEqual(x, y)))).ToList();
|
||||
}
|
||||
|
||||
public static T Assign<T>(T first, T second)
|
||||
{
|
||||
Type type = typeof(T);
|
||||
foreach (PropertyInfo property in type.GetProperties())
|
||||
{
|
||||
if (!property.CanRead || !property.CanWrite)
|
||||
continue;
|
||||
|
||||
object value = property.GetValue(second);
|
||||
property.SetValue(first, value);
|
||||
}
|
||||
|
||||
return first;
|
||||
}
|
||||
|
||||
public static T Complete<T>(T first, T second)
|
||||
{
|
||||
Type type = typeof(T);
|
||||
@ -149,7 +166,7 @@ namespace Kyoo
|
||||
[NotNull] Type owner,
|
||||
[NotNull] string methodName,
|
||||
[NotNull] Type type,
|
||||
IEnumerable<object> args)
|
||||
params object[] args)
|
||||
{
|
||||
if (owner == null)
|
||||
throw new ArgumentNullException(nameof(owner));
|
||||
@ -157,7 +174,7 @@ namespace Kyoo
|
||||
throw new ArgumentNullException(nameof(methodName));
|
||||
if (type == null)
|
||||
throw new ArgumentNullException(nameof(type));
|
||||
MethodInfo method = owner.GetMethod(methodName);
|
||||
MethodInfo method = owner.GetMethod(methodName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
|
||||
if (method == null)
|
||||
throw new NullReferenceException($"A method named {methodName} could not be found on {owner.FullName}");
|
||||
return method.MakeGenericMethod(type).Invoke(null, args?.ToArray());
|
||||
@ -167,7 +184,7 @@ namespace Kyoo
|
||||
[NotNull] object instance,
|
||||
[NotNull] string methodName,
|
||||
[NotNull] Type type,
|
||||
IEnumerable<object> args)
|
||||
params object[] args)
|
||||
{
|
||||
if (instance == null)
|
||||
throw new ArgumentNullException(nameof(instance));
|
||||
@ -175,7 +192,7 @@ namespace Kyoo
|
||||
throw new ArgumentNullException(nameof(methodName));
|
||||
if (type == null)
|
||||
throw new ArgumentNullException(nameof(type));
|
||||
MethodInfo method = instance.GetType().GetMethod(methodName);
|
||||
MethodInfo method = instance.GetType().GetMethod(methodName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
|
||||
if (method == null)
|
||||
throw new NullReferenceException($"A method named {methodName} could not be found on {instance.GetType().FullName}");
|
||||
return method.MakeGenericMethod(type).Invoke(instance, args?.ToArray());
|
||||
@ -230,5 +247,66 @@ namespace Kyoo
|
||||
return string.Empty;
|
||||
return "?" + string.Join('&', query.Select(x => $"{x.Key}={x.Value}"));
|
||||
}
|
||||
|
||||
public static Task<T> Cast<T>(this Task task)
|
||||
{
|
||||
return (Task<T>)task;
|
||||
}
|
||||
|
||||
public static Expression<T> Convert<T>(this Expression expr)
|
||||
where T : Delegate
|
||||
{
|
||||
if (expr is LambdaExpression lambda)
|
||||
return new ExpressionConverter<T>(lambda).VisitAndConvert();
|
||||
throw new ArgumentException("Can't convert a non lambda.");
|
||||
}
|
||||
|
||||
private class ExpressionConverter<TTo> : ExpressionVisitor
|
||||
where TTo : Delegate
|
||||
{
|
||||
private readonly LambdaExpression _expression;
|
||||
private readonly ParameterExpression[] _newParams;
|
||||
|
||||
internal ExpressionConverter(LambdaExpression expression)
|
||||
{
|
||||
_expression = expression;
|
||||
|
||||
Type[] paramTypes = typeof(TTo).GetGenericArguments()[..^1];
|
||||
if (paramTypes.Length != _expression.Parameters.Count)
|
||||
throw new ArgumentException("Parameter count from internal and external lambda are not matched.");
|
||||
|
||||
_newParams = new ParameterExpression[paramTypes.Length];
|
||||
for (int i = 0; i < paramTypes.Length; i++)
|
||||
{
|
||||
if (_expression.Parameters[i].Type == paramTypes[i])
|
||||
_newParams[i] = _expression.Parameters[i];
|
||||
else
|
||||
_newParams[i] = Expression.Parameter(paramTypes[i], _expression.Parameters[i].Name);
|
||||
}
|
||||
}
|
||||
|
||||
internal Expression<TTo> VisitAndConvert()
|
||||
{
|
||||
return (Expression<TTo>)RunGenericMethod(
|
||||
this,
|
||||
"VisitLambda",
|
||||
_expression.GetType().GetGenericArguments().First(),
|
||||
_expression);
|
||||
}
|
||||
|
||||
protected override Expression VisitLambda<T>(Expression<T> node)
|
||||
{
|
||||
Type returnType = _expression.Type.GetGenericArguments().Last();
|
||||
Expression body = node.ReturnType == returnType
|
||||
? Visit(node.Body)
|
||||
: Expression.Convert(Visit(node.Body)!, returnType);
|
||||
return Expression.Lambda<TTo>(body!, _newParams);
|
||||
}
|
||||
|
||||
protected override Expression VisitParameter(ParameterExpression node)
|
||||
{
|
||||
return _newParams.First(x => x.Name == node.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -9,15 +9,16 @@ using Kyoo.CommonApi;
|
||||
using Kyoo.Models;
|
||||
using Kyoo.Models.Exceptions;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Npgsql;
|
||||
|
||||
namespace Kyoo.Controllers
|
||||
{
|
||||
public abstract class LocalRepository<T> : IRepository<T> where T : class, IResource
|
||||
public abstract class LocalRepository<T, TInternal> : IRepository<T>
|
||||
where T : class, IResource
|
||||
where TInternal : class, T
|
||||
{
|
||||
private readonly DbContext _database;
|
||||
|
||||
protected abstract Expression<Func<T, object>> DefaultSort { get; }
|
||||
protected abstract Expression<Func<TInternal, object>> DefaultSort { get; }
|
||||
|
||||
|
||||
protected LocalRepository(DbContext database)
|
||||
@ -35,31 +36,57 @@ namespace Kyoo.Controllers
|
||||
return _database.DisposeAsync();
|
||||
}
|
||||
|
||||
public virtual Task<T> Get(int id)
|
||||
public Task<T> Get(int id)
|
||||
{
|
||||
return _database.Set<T>().FirstOrDefaultAsync(x => x.ID == id);
|
||||
return _Get(id).Cast<T>();
|
||||
}
|
||||
|
||||
public Task<T> Get(string slug)
|
||||
{
|
||||
return _Get(slug).Cast<T>();
|
||||
}
|
||||
|
||||
protected virtual Task<TInternal> _Get(int id)
|
||||
{
|
||||
return _database.Set<TInternal>().FirstOrDefaultAsync(x => x.ID == id);
|
||||
}
|
||||
|
||||
public virtual Task<T> Get(string slug)
|
||||
protected virtual Task<TInternal> _Get(string slug)
|
||||
{
|
||||
return _database.Set<T>().FirstOrDefaultAsync(x => x.Slug == slug);
|
||||
return _database.Set<TInternal>().FirstOrDefaultAsync(x => x.Slug == slug);
|
||||
}
|
||||
|
||||
public abstract Task<ICollection<T>> Search(string query);
|
||||
|
||||
|
||||
public virtual Task<ICollection<T>> GetAll(Expression<Func<T, bool>> where = null,
|
||||
Sort<T> sort = default,
|
||||
Pagination limit = default)
|
||||
{
|
||||
return ApplyFilters(_database.Set<T>(), where, sort, limit);
|
||||
return ApplyFilters(_database.Set<TInternal>(), where, sort, limit);
|
||||
}
|
||||
|
||||
protected Task<ICollection<T>> ApplyFilters(IQueryable<T> query,
|
||||
|
||||
protected async Task<ICollection<T>> ApplyFilters(IQueryable<TInternal> query,
|
||||
Expression<Func<T, bool>> where = null,
|
||||
Sort<T> sort = default,
|
||||
Pagination limit = default)
|
||||
{
|
||||
return ApplyFilters(query, Get, DefaultSort, where, sort, limit);
|
||||
ICollection<TInternal> items = await ApplyFilters(query,
|
||||
_Get,
|
||||
DefaultSort,
|
||||
where.Convert<Func<TInternal, bool>>(),
|
||||
sort.To<TInternal>(),
|
||||
limit);
|
||||
|
||||
return items.ToList<T>();
|
||||
}
|
||||
|
||||
protected async Task<ICollection<T>> ApplyFilters(IQueryable<TInternal> query,
|
||||
Expression<Func<TInternal, bool>> where = null,
|
||||
Sort<TInternal> sort = default,
|
||||
Pagination limit = default)
|
||||
{
|
||||
ICollection<TInternal> items = await ApplyFilters(query, _Get, DefaultSort, where, sort, limit);
|
||||
return items.ToList<T>();
|
||||
}
|
||||
|
||||
protected async Task<ICollection<TValue>> ApplyFilters<TValue>(IQueryable<TValue> query,
|
||||
@ -125,7 +152,7 @@ namespace Kyoo.Controllers
|
||||
if (edited == null)
|
||||
throw new ArgumentNullException(nameof(edited));
|
||||
|
||||
T old = await Get(edited.Slug);
|
||||
TInternal old = (TInternal)await Get(edited.Slug);
|
||||
|
||||
if (old == null)
|
||||
throw new ItemNotFound($"No ressource found with the slug {edited.Slug}.");
|
||||
@ -138,9 +165,9 @@ namespace Kyoo.Controllers
|
||||
return old;
|
||||
}
|
||||
|
||||
protected virtual Task Validate(T ressource)
|
||||
protected virtual Task Validate(TInternal ressource)
|
||||
{
|
||||
foreach (PropertyInfo property in typeof(T).GetProperties()
|
||||
foreach (PropertyInfo property in typeof(TInternal).GetProperties()
|
||||
.Where(x => typeof(IEnumerable).IsAssignableFrom(x.PropertyType)
|
||||
&& !typeof(string).IsAssignableFrom(x.PropertyType)))
|
||||
{
|
||||
|
@ -93,7 +93,7 @@ namespace Kyoo.Controllers
|
||||
show.Slug = Utility.ToSlug(showName);
|
||||
show.Title ??= showName;
|
||||
show.IsMovie = isMovie;
|
||||
show.GenreLinks = show.GenreLinks?.GroupBy(x => x.Genre.Slug).Select(x => x.First()).ToList();
|
||||
show.Genres = show.Genres?.GroupBy(x => x.Slug).Select(x => x.First()).ToList();
|
||||
show.People = show.People?.GroupBy(x => x.Slug).Select(x => x.First()).ToList();
|
||||
return show;
|
||||
}
|
||||
|
@ -10,12 +10,12 @@ using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Kyoo.Controllers
|
||||
{
|
||||
public class CollectionRepository : LocalRepository<Collection>, ICollectionRepository
|
||||
public class CollectionRepository : LocalRepository<Collection, CollectionDE>, ICollectionRepository
|
||||
{
|
||||
private readonly DatabaseContext _database;
|
||||
private readonly Lazy<IShowRepository> _shows;
|
||||
private readonly Lazy<ILibraryRepository> _libraries;
|
||||
protected override Expression<Func<Collection, object>> DefaultSort => x => x.Name;
|
||||
protected override Expression<Func<CollectionDE, object>> DefaultSort => x => x.Name;
|
||||
|
||||
public CollectionRepository(DatabaseContext database, IServiceProvider services) : base(database)
|
||||
{
|
||||
@ -47,7 +47,7 @@ namespace Kyoo.Controllers
|
||||
return await _database.Collections
|
||||
.Where(x => EF.Functions.ILike(x.Name, $"%{query}%"))
|
||||
.Take(20)
|
||||
.ToListAsync();
|
||||
.ToListAsync<Collection>();
|
||||
}
|
||||
|
||||
public override async Task<Collection> Create(Collection obj)
|
||||
@ -60,10 +60,11 @@ namespace Kyoo.Controllers
|
||||
return obj;
|
||||
}
|
||||
|
||||
public override async Task Delete(Collection obj)
|
||||
public override async Task Delete(Collection item)
|
||||
{
|
||||
if (obj == null)
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
if (item == null)
|
||||
throw new ArgumentNullException(nameof(item));
|
||||
CollectionDE obj = new CollectionDE(item);
|
||||
|
||||
_database.Entry(obj).State = EntityState.Deleted;
|
||||
if (obj.Links != null)
|
||||
@ -82,7 +83,7 @@ namespace Kyoo.Controllers
|
||||
{
|
||||
ICollection<Collection> collections = await ApplyFilters(_database.CollectionLinks
|
||||
.Where(x => x.ShowID == showID)
|
||||
.Select(x => x.Collection),
|
||||
.Select(x => x.Collection as CollectionDE),
|
||||
where,
|
||||
sort,
|
||||
limit);
|
||||
@ -98,7 +99,7 @@ namespace Kyoo.Controllers
|
||||
{
|
||||
ICollection<Collection> collections = await ApplyFilters(_database.CollectionLinks
|
||||
.Where(x => x.Show.Slug == showSlug)
|
||||
.Select(x => x.Collection),
|
||||
.Select(x => x.Collection as CollectionDE),
|
||||
where,
|
||||
sort,
|
||||
limit);
|
||||
@ -114,7 +115,7 @@ namespace Kyoo.Controllers
|
||||
{
|
||||
ICollection<Collection> collections = await ApplyFilters(_database.LibraryLinks
|
||||
.Where(x => x.LibraryID == id && x.CollectionID != null)
|
||||
.Select(x => x.Collection),
|
||||
.Select(x => x.Collection as CollectionDE),
|
||||
where,
|
||||
sort,
|
||||
limit);
|
||||
@ -130,7 +131,7 @@ namespace Kyoo.Controllers
|
||||
{
|
||||
ICollection<Collection> collections = await ApplyFilters(_database.LibraryLinks
|
||||
.Where(x => x.Library.Slug == slug && x.CollectionID != null)
|
||||
.Select(x => x.Collection),
|
||||
.Select(x => x.Collection as CollectionDE),
|
||||
where,
|
||||
sort,
|
||||
limit);
|
||||
|
@ -10,7 +10,7 @@ using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Kyoo.Controllers
|
||||
{
|
||||
public class EpisodeRepository : LocalRepository<Episode>, IEpisodeRepository
|
||||
public class EpisodeRepository : LocalRepository<Episode, Episode>, IEpisodeRepository
|
||||
{
|
||||
private readonly DatabaseContext _database;
|
||||
private readonly IProviderRepository _providers;
|
||||
@ -133,7 +133,7 @@ namespace Kyoo.Controllers
|
||||
Sort<Episode> sort = default,
|
||||
Pagination limit = default)
|
||||
{
|
||||
ICollection<Episode> episodes = await ApplyFilters(_database.Episodes.Where(x => x.ShowID == showID),
|
||||
ICollection<Episode> episodes = await ApplyFilters<Episode>(_database.Episodes.Where(x => x.ShowID == showID),
|
||||
where,
|
||||
sort,
|
||||
limit);
|
||||
|
@ -10,12 +10,12 @@ using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Kyoo.Controllers
|
||||
{
|
||||
public class LibraryRepository : LocalRepository<Library>, ILibraryRepository
|
||||
public class LibraryRepository : LocalRepository<Library, LibraryDE>, ILibraryRepository
|
||||
{
|
||||
private readonly DatabaseContext _database;
|
||||
private readonly IProviderRepository _providers;
|
||||
private readonly Lazy<IShowRepository> _shows;
|
||||
protected override Expression<Func<Library, object>> DefaultSort => x => x.ID;
|
||||
protected override Expression<Func<LibraryDE, object>> DefaultSort => x => x.ID;
|
||||
|
||||
|
||||
public LibraryRepository(DatabaseContext database, IProviderRepository providers, IServiceProvider services)
|
||||
@ -47,13 +47,14 @@ namespace Kyoo.Controllers
|
||||
return await _database.Libraries
|
||||
.Where(x => EF.Functions.ILike(x.Name, $"%{query}%"))
|
||||
.Take(20)
|
||||
.ToListAsync();
|
||||
.ToListAsync<Library>();
|
||||
}
|
||||
|
||||
public override async Task<Library> Create(Library obj)
|
||||
public override async Task<Library> Create(Library item)
|
||||
{
|
||||
if (obj == null)
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
if (item == null)
|
||||
throw new ArgumentNullException(nameof(item));
|
||||
LibraryDE obj = new LibraryDE(item);
|
||||
|
||||
await Validate(obj);
|
||||
_database.Entry(obj).State = EntityState.Added;
|
||||
@ -65,7 +66,7 @@ namespace Kyoo.Controllers
|
||||
return obj;
|
||||
}
|
||||
|
||||
protected override async Task Validate(Library obj)
|
||||
protected override async Task Validate(LibraryDE obj)
|
||||
{
|
||||
if (string.IsNullOrEmpty(obj.Slug))
|
||||
throw new ArgumentException("The library's slug must be set and not empty");
|
||||
@ -81,10 +82,11 @@ namespace Kyoo.Controllers
|
||||
link.Provider = await _providers.CreateIfNotExists(link.Provider);
|
||||
}
|
||||
|
||||
public override async Task Delete(Library obj)
|
||||
public override async Task Delete(Library item)
|
||||
{
|
||||
if (obj == null)
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
if (item == null)
|
||||
throw new ArgumentNullException(nameof(item));
|
||||
LibraryDE obj = new LibraryDE(item);
|
||||
|
||||
_database.Entry(obj).State = EntityState.Deleted;
|
||||
if (obj.ProviderLinks != null)
|
||||
@ -103,7 +105,7 @@ namespace Kyoo.Controllers
|
||||
{
|
||||
ICollection<Library> libraries = await ApplyFilters(_database.LibraryLinks
|
||||
.Where(x => x.ShowID == showID)
|
||||
.Select(x => x.Library),
|
||||
.Select(x => x.Library as LibraryDE),
|
||||
where,
|
||||
sort,
|
||||
limit);
|
||||
@ -119,7 +121,7 @@ namespace Kyoo.Controllers
|
||||
{
|
||||
ICollection<Library> libraries = await ApplyFilters(_database.LibraryLinks
|
||||
.Where(x => x.Show.Slug == showSlug)
|
||||
.Select(x => x.Library),
|
||||
.Select(x => x.Library as LibraryDE),
|
||||
where,
|
||||
sort,
|
||||
limit);
|
||||
@ -135,7 +137,7 @@ namespace Kyoo.Controllers
|
||||
{
|
||||
ICollection<Library> libraries = await ApplyFilters(_database.LibraryLinks
|
||||
.Where(x => x.CollectionID == id)
|
||||
.Select(x => x.Library),
|
||||
.Select(x => x.Library as LibraryDE),
|
||||
where,
|
||||
sort,
|
||||
limit);
|
||||
@ -151,7 +153,7 @@ namespace Kyoo.Controllers
|
||||
{
|
||||
ICollection<Library> libraries = await ApplyFilters(_database.LibraryLinks
|
||||
.Where(x => x.Collection.Slug == slug)
|
||||
.Select(x => x.Library),
|
||||
.Select(x => x.Library as LibraryDE),
|
||||
where,
|
||||
sort,
|
||||
limit);
|
||||
|
@ -10,7 +10,7 @@ using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Kyoo.Controllers
|
||||
{
|
||||
public class ShowRepository : LocalRepository<Show>, IShowRepository
|
||||
public class ShowRepository : LocalRepository<Show, ShowDE>, IShowRepository
|
||||
{
|
||||
private readonly DatabaseContext _database;
|
||||
private readonly IStudioRepository _studios;
|
||||
@ -21,7 +21,7 @@ namespace Kyoo.Controllers
|
||||
private readonly Lazy<IEpisodeRepository> _episodes;
|
||||
private readonly Lazy<ILibraryRepository> _libraries;
|
||||
private readonly Lazy<ICollectionRepository> _collections;
|
||||
protected override Expression<Func<Show, object>> DefaultSort => x => x.Title;
|
||||
protected override Expression<Func<ShowDE, object>> DefaultSort => x => x.Title;
|
||||
|
||||
public ShowRepository(DatabaseContext database,
|
||||
IStudioRepository studios,
|
||||
@ -83,13 +83,14 @@ namespace Kyoo.Controllers
|
||||
.Where(x => EF.Functions.ILike(x.Title, query)
|
||||
/*|| x.Aliases.Any(y => EF.Functions.ILike(y, query))*/) // NOT TRANSLATABLE.
|
||||
.Take(20)
|
||||
.ToListAsync();
|
||||
.ToListAsync<Show>();
|
||||
}
|
||||
|
||||
public override async Task<Show> Create(Show obj)
|
||||
public override async Task<Show> Create(Show item)
|
||||
{
|
||||
if (obj == null)
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
if (item == null)
|
||||
throw new ArgumentNullException(nameof(item));
|
||||
ShowDE obj = new ShowDE(item);
|
||||
|
||||
await Validate(obj);
|
||||
_database.Entry(obj).State = EntityState.Added;
|
||||
@ -107,7 +108,7 @@ namespace Kyoo.Controllers
|
||||
return obj;
|
||||
}
|
||||
|
||||
protected override async Task Validate(Show obj)
|
||||
protected override async Task Validate(ShowDE obj)
|
||||
{
|
||||
await base.Validate(obj);
|
||||
|
||||
@ -147,10 +148,11 @@ namespace Kyoo.Controllers
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task Delete(Show obj)
|
||||
public override async Task Delete(Show item)
|
||||
{
|
||||
if (obj == null)
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
if (item == null)
|
||||
throw new ArgumentNullException(nameof(item));
|
||||
ShowDE obj = new ShowDE(item);
|
||||
|
||||
_database.Entry(obj).State = EntityState.Deleted;
|
||||
|
||||
@ -190,7 +192,7 @@ namespace Kyoo.Controllers
|
||||
{
|
||||
ICollection<Show> shows = await ApplyFilters(_database.LibraryLinks
|
||||
.Where(x => x.LibraryID == id && x.ShowID != null)
|
||||
.Select(x => x.Show),
|
||||
.Select(x => x.Show as ShowDE),
|
||||
where,
|
||||
sort,
|
||||
limit);
|
||||
@ -206,7 +208,7 @@ namespace Kyoo.Controllers
|
||||
{
|
||||
ICollection<Show> shows = await ApplyFilters(_database.LibraryLinks
|
||||
.Where(x => x.Library.Slug == slug && x.ShowID != null)
|
||||
.Select(x => x.Show),
|
||||
.Select(x => x.Show as ShowDE),
|
||||
where,
|
||||
sort,
|
||||
limit);
|
||||
@ -222,7 +224,7 @@ namespace Kyoo.Controllers
|
||||
{
|
||||
ICollection<Show> shows = await ApplyFilters(_database.CollectionLinks
|
||||
.Where(x => x.CollectionID== id)
|
||||
.Select(x => x.Show),
|
||||
.Select(x => x.Show as ShowDE),
|
||||
where,
|
||||
sort,
|
||||
limit);
|
||||
@ -238,7 +240,7 @@ namespace Kyoo.Controllers
|
||||
{
|
||||
ICollection<Show> shows = await ApplyFilters(_database.CollectionLinks
|
||||
.Where(x => x.Collection.Slug == slug)
|
||||
.Select(x => x.Show),
|
||||
.Select(x => x.Show as ShowDE),
|
||||
where,
|
||||
sort,
|
||||
limit);
|
||||
@ -249,12 +251,16 @@ namespace Kyoo.Controllers
|
||||
|
||||
public Task<Show> GetFromSeason(int seasonID)
|
||||
{
|
||||
return _database.Shows.FirstOrDefaultAsync(x => x.Seasons.Any(y => y.ID == seasonID));
|
||||
return _database.Shows
|
||||
.FirstOrDefaultAsync(x => x.Seasons.Any(y => y.ID == seasonID))
|
||||
.Cast<Show>();
|
||||
}
|
||||
|
||||
public Task<Show> GetFromEpisode(int episodeID)
|
||||
{
|
||||
return _database.Shows.FirstOrDefaultAsync(x => x.Episodes.Any(y => y.ID == episodeID));
|
||||
return _database.Shows
|
||||
.FirstOrDefaultAsync(x => x.Episodes.Any(y => y.ID == episodeID))
|
||||
.Cast<Show>();
|
||||
}
|
||||
}
|
||||
}
|
@ -96,11 +96,11 @@ namespace Kyoo.Controllers
|
||||
if (episode?.Path == null)
|
||||
return default;
|
||||
|
||||
if (episode.ImgPrimary != null)
|
||||
if (episode.Poster != null)
|
||||
{
|
||||
string localPath = Path.ChangeExtension(episode.Path, "jpg");
|
||||
if (alwaysDownload || !File.Exists(localPath))
|
||||
await DownloadImage(episode.ImgPrimary, localPath, $"The thumbnail of {episode.Show.Title}");
|
||||
await DownloadImage(episode.Poster, localPath, $"The thumbnail of {episode.Show.Title}");
|
||||
}
|
||||
return episode;
|
||||
}
|
||||
|
@ -1,69 +1,27 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using IdentityServer4.EntityFramework.Entities;
|
||||
using IdentityServer4.EntityFramework.Extensions;
|
||||
using IdentityServer4.EntityFramework.Interfaces;
|
||||
using IdentityServer4.EntityFramework.Options;
|
||||
using Kyoo.Models;
|
||||
using Kyoo.Models.Exceptions;
|
||||
using Kyoo.Models.Watch;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.ChangeTracking;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Npgsql;
|
||||
|
||||
namespace Kyoo
|
||||
{
|
||||
public class IdentityDatabase : IdentityDbContext<User>, IPersistedGrantDbContext
|
||||
{
|
||||
private readonly IOptions<OperationalStoreOptions> _operationalStoreOptions;
|
||||
|
||||
public IdentityDatabase(DbContextOptions<IdentityDatabase> options, IOptions<OperationalStoreOptions> operationalStoreOptions)
|
||||
: base(options)
|
||||
{
|
||||
_operationalStoreOptions = operationalStoreOptions;
|
||||
}
|
||||
|
||||
public DbSet<User> Accounts { get; set; }
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
base.OnModelCreating(modelBuilder);
|
||||
modelBuilder.ConfigurePersistedGrantContext(_operationalStoreOptions.Value);
|
||||
|
||||
modelBuilder.Entity<User>().ToTable("User");
|
||||
modelBuilder.Entity<IdentityUserRole<string>>().ToTable("UserRole");
|
||||
modelBuilder.Entity<IdentityUserLogin<string>>().ToTable("UserLogin");
|
||||
modelBuilder.Entity<IdentityUserClaim<string>>().ToTable("UserClaim");
|
||||
modelBuilder.Entity<IdentityRole>().ToTable("UserRoles");
|
||||
modelBuilder.Entity<IdentityRoleClaim<string>>().ToTable("UserRoleClaim");
|
||||
modelBuilder.Entity<IdentityUserToken<string>>().ToTable("UserToken");
|
||||
}
|
||||
|
||||
public Task<int> SaveChangesAsync() => base.SaveChangesAsync();
|
||||
|
||||
public DbSet<PersistedGrant> PersistedGrants { get; set; }
|
||||
public DbSet<DeviceFlowCodes> DeviceFlowCodes { get; set; }
|
||||
|
||||
}
|
||||
|
||||
public class DatabaseContext : DbContext
|
||||
{
|
||||
public DatabaseContext(DbContextOptions<DatabaseContext> options) : base(options) { }
|
||||
|
||||
public DbSet<Library> Libraries { get; set; }
|
||||
public DbSet<Collection> Collections { get; set; }
|
||||
public DbSet<Show> Shows { get; set; }
|
||||
public DbSet<LibraryDE> Libraries { get; set; }
|
||||
public DbSet<CollectionDE> Collections { get; set; }
|
||||
public DbSet<ShowDE> Shows { get; set; }
|
||||
public DbSet<Season> Seasons { get; set; }
|
||||
public DbSet<Episode> Episodes { get; set; }
|
||||
public DbSet<Track> Tracks { get; set; }
|
||||
public DbSet<Genre> Genres { get; set; }
|
||||
public DbSet<GenreDE> Genres { get; set; }
|
||||
public DbSet<People> People { get; set; }
|
||||
public DbSet<Studio> Studios { get; set; }
|
||||
public DbSet<ProviderID> Providers { get; set; }
|
||||
@ -72,7 +30,6 @@ namespace Kyoo
|
||||
public DbSet<PeopleRole> PeopleRoles { get; set; }
|
||||
|
||||
|
||||
// This is used because EF doesn't support Many-To-Many relationships so for now we need to override the getter/setters to store this.
|
||||
public DbSet<LibraryLink> LibraryLinks { get; set; }
|
||||
public DbSet<CollectionLink> CollectionLinks { get; set; }
|
||||
public DbSet<GenreLink> GenreLinks { get; set; }
|
||||
|
46
Kyoo/Models/IdentityDatabase.cs
Normal file
46
Kyoo/Models/IdentityDatabase.cs
Normal file
@ -0,0 +1,46 @@
|
||||
using System.Threading.Tasks;
|
||||
using IdentityServer4.EntityFramework.Entities;
|
||||
using IdentityServer4.EntityFramework.Extensions;
|
||||
using IdentityServer4.EntityFramework.Interfaces;
|
||||
using IdentityServer4.EntityFramework.Options;
|
||||
using Kyoo.Models;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Kyoo
|
||||
{
|
||||
public class IdentityDatabase : IdentityDbContext<User>, IPersistedGrantDbContext
|
||||
{
|
||||
private readonly IOptions<OperationalStoreOptions> _operationalStoreOptions;
|
||||
|
||||
public IdentityDatabase(DbContextOptions<IdentityDatabase> options, IOptions<OperationalStoreOptions> operationalStoreOptions)
|
||||
: base(options)
|
||||
{
|
||||
_operationalStoreOptions = operationalStoreOptions;
|
||||
}
|
||||
|
||||
public DbSet<User> Accounts { get; set; }
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
base.OnModelCreating(modelBuilder);
|
||||
modelBuilder.ConfigurePersistedGrantContext(_operationalStoreOptions.Value);
|
||||
|
||||
modelBuilder.Entity<User>().ToTable("User");
|
||||
modelBuilder.Entity<IdentityUserRole<string>>().ToTable("UserRole");
|
||||
modelBuilder.Entity<IdentityUserLogin<string>>().ToTable("UserLogin");
|
||||
modelBuilder.Entity<IdentityUserClaim<string>>().ToTable("UserClaim");
|
||||
modelBuilder.Entity<IdentityRole>().ToTable("UserRoles");
|
||||
modelBuilder.Entity<IdentityRoleClaim<string>>().ToTable("UserRoleClaim");
|
||||
modelBuilder.Entity<IdentityUserToken<string>>().ToTable("UserToken");
|
||||
}
|
||||
|
||||
public Task<int> SaveChangesAsync() => base.SaveChangesAsync();
|
||||
|
||||
public DbSet<PersistedGrant> PersistedGrants { get; set; }
|
||||
public DbSet<DeviceFlowCodes> DeviceFlowCodes { get; set; }
|
||||
|
||||
}
|
||||
}
|
30
Kyoo/Models/Resources/CollectionDE.cs
Normal file
30
Kyoo/Models/Resources/CollectionDE.cs
Normal file
@ -0,0 +1,30 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Kyoo.Models.Attributes;
|
||||
|
||||
namespace Kyoo.Models
|
||||
{
|
||||
public class CollectionDE : Collection
|
||||
{
|
||||
[NotMergable] public virtual IEnumerable<CollectionLink> Links { get; set; }
|
||||
public override IEnumerable<Show> Shows
|
||||
{
|
||||
get => Links.Select(x => x.Show);
|
||||
set => Links = value.Select(x => new CollectionLink(this, x));
|
||||
}
|
||||
|
||||
[NotMergable] public virtual IEnumerable<LibraryLink> LibraryLinks { get; set; }
|
||||
public override IEnumerable<Library> Libraries
|
||||
{
|
||||
get => LibraryLinks?.Select(x => x.Library);
|
||||
set => LibraryLinks = value?.Select(x => new LibraryLink(x, this));
|
||||
}
|
||||
|
||||
public CollectionDE() {}
|
||||
|
||||
public CollectionDE(Collection collection)
|
||||
{
|
||||
Utility.Assign(this, collection);
|
||||
}
|
||||
}
|
||||
}
|
24
Kyoo/Models/Resources/GenreDE.cs
Normal file
24
Kyoo/Models/Resources/GenreDE.cs
Normal file
@ -0,0 +1,24 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Kyoo.Models.Attributes;
|
||||
|
||||
namespace Kyoo.Models
|
||||
{
|
||||
public class GenreDE : Genre
|
||||
{
|
||||
[NotMergable] public virtual IEnumerable<GenreLink> Links { get; set; }
|
||||
|
||||
[NotMergable] public override IEnumerable<Show> Shows
|
||||
{
|
||||
get => Links.Select(x => x.Show);
|
||||
set => Links = value?.Select(x => new GenreLink(x, this));
|
||||
}
|
||||
|
||||
public GenreDE() {}
|
||||
|
||||
public GenreDE(Genre item)
|
||||
{
|
||||
Utility.Assign(this, item);
|
||||
}
|
||||
}
|
||||
}
|
39
Kyoo/Models/Resources/LibraryDE.cs
Normal file
39
Kyoo/Models/Resources/LibraryDE.cs
Normal file
@ -0,0 +1,39 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Kyoo.Models.Attributes;
|
||||
|
||||
namespace Kyoo.Models
|
||||
{
|
||||
public class LibraryDE : Library
|
||||
{
|
||||
[NotMergable] public virtual IEnumerable<ProviderLink> ProviderLinks { get; set; }
|
||||
public override IEnumerable<ProviderID> Providers
|
||||
{
|
||||
get => ProviderLinks?.Select(x => x.Provider);
|
||||
set => ProviderLinks = value.Select(x => new ProviderLink(x, this)).ToList();
|
||||
}
|
||||
|
||||
[NotMergable] public virtual IEnumerable<LibraryLink> Links { get; set; }
|
||||
public override IEnumerable<Show> Shows
|
||||
{
|
||||
get => Links?.Where(x => x.Show != null).Select(x => x.Show);
|
||||
set => Links = Utility.MergeLists(
|
||||
value?.Select(x => new LibraryLink(this, x)),
|
||||
Links?.Where(x => x.Show == null));
|
||||
}
|
||||
public override IEnumerable<Collection> Collections
|
||||
{
|
||||
get => Links?.Where(x => x.Collection != null).Select(x => x.Collection);
|
||||
set => Links = Utility.MergeLists(
|
||||
value?.Select(x => new LibraryLink(this, x)),
|
||||
Links?.Where(x => x.Collection == null));
|
||||
}
|
||||
|
||||
public LibraryDE() {}
|
||||
|
||||
public LibraryDE(Library item)
|
||||
{
|
||||
Utility.Assign(this, item);
|
||||
}
|
||||
}
|
||||
}
|
47
Kyoo/Models/Resources/ShowDE.cs
Normal file
47
Kyoo/Models/Resources/ShowDE.cs
Normal file
@ -0,0 +1,47 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Kyoo.Models.Attributes;
|
||||
|
||||
namespace Kyoo.Models
|
||||
{
|
||||
public class ShowDE : Show
|
||||
{
|
||||
[NotMergable] public virtual IEnumerable<GenreLink> GenreLinks { get; set; }
|
||||
public override IEnumerable<Genre> Genres
|
||||
{
|
||||
get => GenreLinks?.Select(x => x.Genre);
|
||||
set => GenreLinks = value?.Select(x => new GenreLink(this, x)).ToList();
|
||||
}
|
||||
|
||||
[NotMergable] public virtual IEnumerable<LibraryLink> LibraryLinks { get; set; }
|
||||
public override IEnumerable<Library> Libraries
|
||||
{
|
||||
get => LibraryLinks?.Select(x => x.Library);
|
||||
set => LibraryLinks = value?.Select(x => new LibraryLink(x, this));
|
||||
}
|
||||
|
||||
[NotMergable] public virtual IEnumerable<CollectionLink> CollectionLinks { get; set; }
|
||||
|
||||
public override IEnumerable<Collection> Collections
|
||||
{
|
||||
get => CollectionLinks?.Select(x => x.Collection);
|
||||
set => CollectionLinks = value?.Select(x => new CollectionLink(x, this));
|
||||
}
|
||||
|
||||
public override void OnMerge(object merged)
|
||||
{
|
||||
base.OnMerge(merged);
|
||||
|
||||
if (GenreLinks != null)
|
||||
foreach (GenreLink genre in GenreLinks)
|
||||
genre.Show = this;
|
||||
}
|
||||
|
||||
public ShowDE() {}
|
||||
|
||||
public ShowDE(Show show)
|
||||
{
|
||||
Utility.Assign(this, show);
|
||||
}
|
||||
}
|
||||
}
|
@ -1 +1 @@
|
||||
Subproject commit d4202623007f0cefb22aa64e3c638142ba7d7831
|
||||
Subproject commit 2e44a86c4b9004012c10d259ae90925adcd66aa7
|
Loading…
x
Reference in New Issue
Block a user