mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-07-09 03:04:20 -04:00
Reworking metadata handling and adding it to Collections and Studios
This commit is contained in:
parent
3262343c4a
commit
2812c9cacf
@ -590,10 +590,10 @@ namespace Kyoo.Controllers
|
|||||||
/// <param name="limit">Pagination information (where to start and how many to get)</param>
|
/// <param name="limit">Pagination information (where to start and how many to get)</param>
|
||||||
/// <typeparam name="T">The type of metadata to retrieve</typeparam>
|
/// <typeparam name="T">The type of metadata to retrieve</typeparam>
|
||||||
/// <returns>A filtered list of external ids.</returns>
|
/// <returns>A filtered list of external ids.</returns>
|
||||||
Task<ICollection<MetadataID<T>>> GetMetadataID<T>(Expression<Func<MetadataID<T>, bool>> where = null,
|
Task<ICollection<MetadataID>> GetMetadataID<T>(Expression<Func<MetadataID, bool>> where = null,
|
||||||
Sort<MetadataID<T>> sort = default,
|
Sort<MetadataID> sort = default,
|
||||||
Pagination limit = default)
|
Pagination limit = default)
|
||||||
where T : class, IResource;
|
where T : class, IMetadata;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get a list of external ids that match all filters
|
/// Get a list of external ids that match all filters
|
||||||
@ -602,11 +602,11 @@ namespace Kyoo.Controllers
|
|||||||
/// <param name="sort">A sort by expression</param>
|
/// <param name="sort">A sort by expression</param>
|
||||||
/// <param name="limit">Pagination information (where to start and how many to get)</param>
|
/// <param name="limit">Pagination information (where to start and how many to get)</param>
|
||||||
/// <returns>A filtered list of external ids.</returns>
|
/// <returns>A filtered list of external ids.</returns>
|
||||||
Task<ICollection<MetadataID<T>>> GetMetadataID<T>([Optional] Expression<Func<MetadataID<T>, bool>> where,
|
Task<ICollection<MetadataID>> GetMetadataID<T>([Optional] Expression<Func<MetadataID, bool>> where,
|
||||||
Expression<Func<MetadataID<T>, object>> sort,
|
Expression<Func<MetadataID, object>> sort,
|
||||||
Pagination limit = default
|
Pagination limit = default
|
||||||
) where T : class, IResource
|
) where T : class, IMetadata
|
||||||
=> GetMetadataID(where, new Sort<MetadataID<T>>(sort), limit);
|
=> GetMetadataID<T>(where, new Sort<MetadataID>(sort), limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -231,7 +231,12 @@ namespace Kyoo.Controllers
|
|||||||
.Then(x => l.Collections = x),
|
.Then(x => l.Collections = x),
|
||||||
|
|
||||||
|
|
||||||
(Collection c, nameof(Library.Shows)) => ShowRepository
|
(Collection c, nameof(Collection.ExternalIDs)) => SetRelation(c,
|
||||||
|
ProviderRepository.GetMetadataID<Collection>(x => x.ResourceID == obj.ID),
|
||||||
|
(x, y) => x.ExternalIDs = y,
|
||||||
|
(x, y) => { x.ResourceID = y.ID; }),
|
||||||
|
|
||||||
|
(Collection c, nameof(Collection.Shows)) => ShowRepository
|
||||||
.GetAll(x => x.Collections.Any(y => y.ID == obj.ID))
|
.GetAll(x => x.Collections.Any(y => y.ID == obj.ID))
|
||||||
.Then(x => c.Shows = x),
|
.Then(x => c.Shows = x),
|
||||||
|
|
||||||
@ -241,9 +246,9 @@ namespace Kyoo.Controllers
|
|||||||
|
|
||||||
|
|
||||||
(Show s, nameof(Show.ExternalIDs)) => SetRelation(s,
|
(Show s, nameof(Show.ExternalIDs)) => SetRelation(s,
|
||||||
ProviderRepository.GetMetadataID<Show>(x => x.FirstID == obj.ID),
|
ProviderRepository.GetMetadataID<Show>(x => x.ResourceID == obj.ID),
|
||||||
(x, y) => x.ExternalIDs = y,
|
(x, y) => x.ExternalIDs = y,
|
||||||
(x, y) => { x.First = y; x.FirstID = y.ID; }),
|
(x, y) => { x.ResourceID = y.ID; }),
|
||||||
|
|
||||||
(Show s, nameof(Show.Genres)) => GenreRepository
|
(Show s, nameof(Show.Genres)) => GenreRepository
|
||||||
.GetAll(x => x.Shows.Any(y => y.ID == obj.ID))
|
.GetAll(x => x.Shows.Any(y => y.ID == obj.ID))
|
||||||
@ -281,9 +286,9 @@ namespace Kyoo.Controllers
|
|||||||
|
|
||||||
|
|
||||||
(Season s, nameof(Season.ExternalIDs)) => SetRelation(s,
|
(Season s, nameof(Season.ExternalIDs)) => SetRelation(s,
|
||||||
ProviderRepository.GetMetadataID<Season>(x => x.FirstID == obj.ID),
|
ProviderRepository.GetMetadataID<Season>(x => x.ResourceID == obj.ID),
|
||||||
(x, y) => x.ExternalIDs = y,
|
(x, y) => x.ExternalIDs = y,
|
||||||
(x, y) => { x.First = y; x.FirstID = y.ID; }),
|
(x, y) => { x.ResourceID = y.ID; }),
|
||||||
|
|
||||||
(Season s, nameof(Season.Episodes)) => SetRelation(s,
|
(Season s, nameof(Season.Episodes)) => SetRelation(s,
|
||||||
EpisodeRepository.GetAll(x => x.Season.ID == obj.ID),
|
EpisodeRepository.GetAll(x => x.Season.ID == obj.ID),
|
||||||
@ -300,9 +305,9 @@ namespace Kyoo.Controllers
|
|||||||
|
|
||||||
|
|
||||||
(Episode e, nameof(Episode.ExternalIDs)) => SetRelation(e,
|
(Episode e, nameof(Episode.ExternalIDs)) => SetRelation(e,
|
||||||
ProviderRepository.GetMetadataID<Episode>(x => x.FirstID == obj.ID),
|
ProviderRepository.GetMetadataID<Episode>(x => x.ResourceID == obj.ID),
|
||||||
(x, y) => x.ExternalIDs = y,
|
(x, y) => x.ExternalIDs = y,
|
||||||
(x, y) => { x.First = y; x.FirstID = y.ID; }),
|
(x, y) => { x.ResourceID = y.ID; }),
|
||||||
|
|
||||||
(Episode e, nameof(Episode.Tracks)) => SetRelation(e,
|
(Episode e, nameof(Episode.Tracks)) => SetRelation(e,
|
||||||
TrackRepository.GetAll(x => x.Episode.ID == obj.ID),
|
TrackRepository.GetAll(x => x.Episode.ID == obj.ID),
|
||||||
@ -344,11 +349,16 @@ namespace Kyoo.Controllers
|
|||||||
.GetAll(x => x.Studio.ID == obj.ID)
|
.GetAll(x => x.Studio.ID == obj.ID)
|
||||||
.Then(x => s.Shows = x),
|
.Then(x => s.Shows = x),
|
||||||
|
|
||||||
|
(Studio s, nameof(Studio.ExternalIDs)) => SetRelation(s,
|
||||||
|
ProviderRepository.GetMetadataID<Studio>(x => x.ResourceID == obj.ID),
|
||||||
|
(x, y) => x.ExternalIDs = y,
|
||||||
|
(x, y) => { x.ResourceID = y.ID; }),
|
||||||
|
|
||||||
|
|
||||||
(People p, nameof(People.ExternalIDs)) => SetRelation(p,
|
(People p, nameof(People.ExternalIDs)) => SetRelation(p,
|
||||||
ProviderRepository.GetMetadataID<People>(x => x.FirstID == obj.ID),
|
ProviderRepository.GetMetadataID<People>(x => x.ResourceID == obj.ID),
|
||||||
(x, y) => x.ExternalIDs = y,
|
(x, y) => x.ExternalIDs = y,
|
||||||
(x, y) => { x.First = y; x.FirstID = y.ID; }),
|
(x, y) => { x.ResourceID = y.ID; }),
|
||||||
|
|
||||||
(People p, nameof(People.Roles)) => PeopleRepository
|
(People p, nameof(People.Roles)) => PeopleRepository
|
||||||
.GetFromPeople(obj.ID)
|
.GetFromPeople(obj.ID)
|
||||||
|
@ -92,7 +92,7 @@ namespace Kyoo.Models
|
|||||||
get
|
get
|
||||||
{
|
{
|
||||||
return x => new {First = x.FirstID, Second = x.SecondID};
|
return x => new {First = x.FirstID, Second = x.SecondID};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,7 +157,7 @@ namespace Kyoo.Models
|
|||||||
get
|
get
|
||||||
{
|
{
|
||||||
return x => new {First = x.FirstID, Second = x.SecondID};
|
return x => new {First = x.FirstID, Second = x.SecondID};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,15 +1,34 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq.Expressions;
|
using System.Linq.Expressions;
|
||||||
|
using Kyoo.Models.Attributes;
|
||||||
|
|
||||||
namespace Kyoo.Models
|
namespace Kyoo.Models
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ID and link of an item on an external provider.
|
/// ID and link of an item on an external provider.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T"></typeparam>
|
public class MetadataID
|
||||||
public class MetadataID<T> : Link<T, Provider>
|
|
||||||
where T : class, IResource
|
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The ID of the resource which possess the metadata.
|
||||||
|
/// </summary>
|
||||||
|
[SerializeIgnore] public int ResourceID { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The name of the resource type. This is only used internally to discriminate types.
|
||||||
|
/// </summary>
|
||||||
|
[SerializeIgnore] public string ResourceType { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The ID of the provider.
|
||||||
|
/// </summary>
|
||||||
|
[SerializeIgnore] public int ProviderID { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The provider that can do something with this ID.
|
||||||
|
/// </summary>
|
||||||
|
public Provider Provider { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The ID of the resource on the external provider.
|
/// The ID of the resource on the external provider.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -20,20 +39,14 @@ namespace Kyoo.Models
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string Link { get; set; }
|
public string Link { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A shortcut to access the provider of this metadata.
|
|
||||||
/// Unlike the <see cref="Link{T, T2}.Second"/> property, this is serializable.
|
|
||||||
/// </summary>
|
|
||||||
public Provider Provider => Second;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The expression to retrieve the unique ID of a MetadataID. This is an aggregate of the two resources IDs.
|
/// The expression to retrieve the unique ID of a MetadataID. This is an aggregate of the two resources IDs.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public new static Expression<Func<MetadataID<T>, object>> PrimaryKey
|
public static Expression<Func<MetadataID, object>> PrimaryKey
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return x => new {First = x.FirstID, Second = x.SecondID};
|
return x => new {First = x.ResourceID, Second = x.ProviderID, Type = x.ResourceType};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ namespace Kyoo.Models
|
|||||||
/// A class representing collections of <see cref="Show"/>.
|
/// A class representing collections of <see cref="Show"/>.
|
||||||
/// A collection can also be stored in a <see cref="Library"/>.
|
/// A collection can also be stored in a <see cref="Library"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Collection : IResource
|
public class Collection : IResource, IMetadata
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public int ID { get; set; }
|
public int ID { get; set; }
|
||||||
@ -42,6 +42,9 @@ namespace Kyoo.Models
|
|||||||
/// The list of libraries that contains this collection.
|
/// The list of libraries that contains this collection.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[LoadableRelation] public ICollection<Library> Libraries { get; set; }
|
[LoadableRelation] public ICollection<Library> Libraries { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public ICollection<MetadataID> ExternalIDs { get; set; }
|
||||||
|
|
||||||
#if ENABLE_INTERNAL_LINKS
|
#if ENABLE_INTERNAL_LINKS
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ namespace Kyoo.Models
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// A class to represent a single show's episode.
|
/// A class to represent a single show's episode.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Episode : IResource
|
public class Episode : IResource, IMetadata
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public int ID { get; set; }
|
public int ID { get; set; }
|
||||||
@ -121,10 +121,8 @@ namespace Kyoo.Models
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public DateTime? ReleaseDate { get; set; }
|
public DateTime? ReleaseDate { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <inheritdoc />
|
||||||
/// The link to metadata providers that this episode has. See <see cref="MetadataID{T}"/> for more information.
|
public ICollection<MetadataID> ExternalIDs { get; set; }
|
||||||
/// </summary>
|
|
||||||
[EditableRelation] [LoadableRelation] public ICollection<MetadataID<Episode>> ExternalIDs { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The list of tracks this episode has. This lists video, audio and subtitles available.
|
/// The list of tracks this episode has. This lists video, audio and subtitles available.
|
||||||
|
16
Kyoo.Common/Models/Resources/Interfaces/IMetadata.cs
Normal file
16
Kyoo.Common/Models/Resources/Interfaces/IMetadata.cs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using Kyoo.Models.Attributes;
|
||||||
|
|
||||||
|
namespace Kyoo.Models
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// An interface applied to resources containing external metadata.
|
||||||
|
/// </summary>
|
||||||
|
public interface IMetadata
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The link to metadata providers that this show has. See <see cref="MetadataID"/> for more information.
|
||||||
|
/// </summary>
|
||||||
|
[EditableRelation] [LoadableRelation] public ICollection<MetadataID> ExternalIDs { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -6,7 +6,7 @@ namespace Kyoo.Models
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// An actor, voice actor, writer, animator, somebody who worked on a <see cref="Show"/>.
|
/// An actor, voice actor, writer, animator, somebody who worked on a <see cref="Show"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class People : IResource
|
public class People : IResource, IMetadata
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public int ID { get; set; }
|
public int ID { get; set; }
|
||||||
@ -26,10 +26,8 @@ namespace Kyoo.Models
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[SerializeAs("{HOST}/api/people/{Slug}/poster")] public string Poster { get; set; }
|
[SerializeAs("{HOST}/api/people/{Slug}/poster")] public string Poster { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <inheritdoc />
|
||||||
/// The link to metadata providers that this person has. See <see cref="MetadataID{T}"/> for more information.
|
public ICollection<MetadataID> ExternalIDs { get; set; }
|
||||||
/// </summary>
|
|
||||||
[EditableRelation] [LoadableRelation] public ICollection<MetadataID<People>> ExternalIDs { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The list of roles this person has played in. See <see cref="PeopleRole"/> for more information.
|
/// The list of roles this person has played in. See <see cref="PeopleRole"/> for more information.
|
||||||
|
@ -10,7 +10,7 @@ namespace Kyoo.Models
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// A season of a <see cref="Show"/>.
|
/// A season of a <see cref="Show"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Season : IResource
|
public class Season : IResource, IMetadata
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public int ID { get; set; }
|
public int ID { get; set; }
|
||||||
@ -81,10 +81,8 @@ namespace Kyoo.Models
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[SerializeAs("{HOST}/api/seasons/{Slug}/thumb")] public string Poster { get; set; }
|
[SerializeAs("{HOST}/api/seasons/{Slug}/thumb")] public string Poster { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <inheritdoc />
|
||||||
/// The link to metadata providers that this episode has. See <see cref="MetadataID{T}"/> for more information.
|
public ICollection<MetadataID> ExternalIDs { get; set; }
|
||||||
/// </summary>
|
|
||||||
[EditableRelation] [LoadableRelation] public ICollection<MetadataID<Season>> ExternalIDs { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The list of episodes that this season contains.
|
/// The list of episodes that this season contains.
|
||||||
|
@ -11,7 +11,7 @@ namespace Kyoo.Models
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// A series or a movie.
|
/// A series or a movie.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Show : IResource, IOnMerge
|
public class Show : IResource, IMetadata, IOnMerge
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public int ID { get; set; }
|
public int ID { get; set; }
|
||||||
@ -89,11 +89,9 @@ namespace Kyoo.Models
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsMovie { get; set; }
|
public bool IsMovie { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <inheritdoc />
|
||||||
/// The link to metadata providers that this show has. See <see cref="MetadataID{T}"/> for more information.
|
public ICollection<MetadataID> ExternalIDs { get; set; }
|
||||||
/// </summary>
|
|
||||||
[EditableRelation] [LoadableRelation] public ICollection<MetadataID<Show>> ExternalIDs { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The ID of the Studio that made this show.
|
/// The ID of the Studio that made this show.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -157,19 +155,16 @@ namespace Kyoo.Models
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>This method will never return anything if the <see cref="ExternalIDs"/> are not loaded.</remarks>
|
/// <remarks>This method will never return anything if the <see cref="ExternalIDs"/> are not loaded.</remarks>
|
||||||
/// <param name="provider">The slug of the provider</param>
|
/// <param name="provider">The slug of the provider</param>
|
||||||
/// <returns>The <see cref="MetadataID{T}.DataID"/> field of the asked provider.</returns>
|
/// <returns>The <see cref="MetadataID.DataID"/> field of the asked provider.</returns>
|
||||||
[CanBeNull]
|
[CanBeNull]
|
||||||
public string GetID(string provider)
|
public string GetID(string provider)
|
||||||
{
|
{
|
||||||
return ExternalIDs?.FirstOrDefault(x => x.Second.Slug == provider)?.DataID;
|
return ExternalIDs?.FirstOrDefault(x => x.Provider.Slug == provider)?.DataID;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void OnMerge(object merged)
|
public void OnMerge(object merged)
|
||||||
{
|
{
|
||||||
if (ExternalIDs != null)
|
|
||||||
foreach (MetadataID<Show> id in ExternalIDs)
|
|
||||||
id.First = this;
|
|
||||||
if (People != null)
|
if (People != null)
|
||||||
foreach (PeopleRole link in People)
|
foreach (PeopleRole link in People)
|
||||||
link.Show = this;
|
link.Show = this;
|
||||||
|
@ -6,7 +6,7 @@ namespace Kyoo.Models
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// A studio that make shows.
|
/// A studio that make shows.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Studio : IResource
|
public class Studio : IResource, IMetadata
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public int ID { get; set; }
|
public int ID { get; set; }
|
||||||
@ -24,6 +24,9 @@ namespace Kyoo.Models
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[LoadableRelation] public ICollection<Show> Shows { get; set; }
|
[LoadableRelation] public ICollection<Show> Shows { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public ICollection<MetadataID> ExternalIDs { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a new, empty, <see cref="Studio"/>.
|
/// Create a new, empty, <see cref="Studio"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -61,6 +61,10 @@ namespace Kyoo
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public DbSet<Provider> Providers { get; set; }
|
public DbSet<Provider> Providers { get; set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
/// All metadata ids, not discriminated by type. See <see cref="MetadataID"/>.
|
||||||
|
/// </summary>
|
||||||
|
public DbSet<MetadataID> MetadataIDs { get; set; }
|
||||||
|
/// <summary>
|
||||||
/// The list of registered users.
|
/// The list of registered users.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public DbSet<User> Users { get; set; }
|
public DbSet<User> Users { get; set; }
|
||||||
@ -83,17 +87,6 @@ namespace Kyoo
|
|||||||
/// </remarks>
|
/// </remarks>
|
||||||
public DbSet<LibraryItem> LibraryItems { get; set; }
|
public DbSet<LibraryItem> LibraryItems { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get all metadataIDs (ExternalIDs) of a given resource. See <see cref="MetadataID{T}"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">The metadata of this type will be returned.</typeparam>
|
|
||||||
/// <returns>A queryable of metadata ids for a type.</returns>
|
|
||||||
public DbSet<MetadataID<T>> MetadataIds<T>()
|
|
||||||
where T : class, IResource
|
|
||||||
{
|
|
||||||
return Set<MetadataID<T>>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get a generic link between two resource types.
|
/// Get a generic link between two resource types.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -132,6 +125,22 @@ namespace Kyoo
|
|||||||
optionsBuilder.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
|
optionsBuilder.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Build the metadata model for the given type.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="modelBuilder">The database model builder</param>
|
||||||
|
/// <typeparam name="T">The type to add metadata to.</typeparam>
|
||||||
|
private void _HasMetadata<T>(ModelBuilder modelBuilder)
|
||||||
|
where T : class, IMetadata
|
||||||
|
{
|
||||||
|
modelBuilder.Entity<T>()
|
||||||
|
.HasMany(x => x.ExternalIDs)
|
||||||
|
.WithOne()
|
||||||
|
.HasForeignKey(x => x.ResourceID)
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Set database parameters to support every types of Kyoo.
|
/// Set database parameters to support every types of Kyoo.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -234,43 +243,21 @@ namespace Kyoo
|
|||||||
.WithMany(x => x.ShowLinks),
|
.WithMany(x => x.ShowLinks),
|
||||||
y => y.HasKey(Link<User, Show>.PrimaryKey));
|
y => y.HasKey(Link<User, Show>.PrimaryKey));
|
||||||
|
|
||||||
modelBuilder.Entity<MetadataID<Show>>()
|
modelBuilder.Entity<MetadataID>()
|
||||||
.HasKey(MetadataID<Show>.PrimaryKey);
|
.HasKey(MetadataID.PrimaryKey);
|
||||||
modelBuilder.Entity<MetadataID<Show>>()
|
modelBuilder.Entity<MetadataID>()
|
||||||
.HasOne(x => x.First)
|
.Property(x => x.ResourceType)
|
||||||
.WithMany(x => x.ExternalIDs)
|
.IsRequired();
|
||||||
.OnDelete(DeleteBehavior.Cascade);
|
modelBuilder.Entity<MetadataID>()
|
||||||
modelBuilder.Entity<MetadataID<Season>>()
|
.HasDiscriminator(x => x.ResourceType);
|
||||||
.HasKey(MetadataID<Season>.PrimaryKey);
|
|
||||||
modelBuilder.Entity<MetadataID<Season>>()
|
|
||||||
.HasOne(x => x.First)
|
|
||||||
.WithMany(x => x.ExternalIDs)
|
|
||||||
.OnDelete(DeleteBehavior.Cascade);
|
|
||||||
modelBuilder.Entity<MetadataID<Episode>>()
|
|
||||||
.HasKey(MetadataID<Episode>.PrimaryKey);
|
|
||||||
modelBuilder.Entity<MetadataID<Episode>>()
|
|
||||||
.HasOne(x => x.First)
|
|
||||||
.WithMany(x => x.ExternalIDs)
|
|
||||||
.OnDelete(DeleteBehavior.Cascade);
|
|
||||||
modelBuilder.Entity<MetadataID<People>>()
|
|
||||||
.HasKey(MetadataID<People>.PrimaryKey);
|
|
||||||
modelBuilder.Entity<MetadataID<People>>()
|
|
||||||
.HasOne(x => x.First)
|
|
||||||
.WithMany(x => x.ExternalIDs)
|
|
||||||
.OnDelete(DeleteBehavior.Cascade);
|
|
||||||
|
|
||||||
|
|
||||||
modelBuilder.Entity<MetadataID<Show>>().HasOne(x => x.Second).WithMany()
|
|
||||||
.OnDelete(DeleteBehavior.Cascade);
|
|
||||||
modelBuilder.Entity<MetadataID<Season>>().HasOne(x => x.Second).WithMany()
|
|
||||||
.OnDelete(DeleteBehavior.Cascade);
|
|
||||||
modelBuilder.Entity<MetadataID<Episode>>().HasOne(x => x.Second).WithMany()
|
|
||||||
.OnDelete(DeleteBehavior.Cascade);
|
|
||||||
modelBuilder.Entity<MetadataID<People>>().HasOne(x => x.Second).WithMany()
|
|
||||||
.OnDelete(DeleteBehavior.Cascade);
|
|
||||||
modelBuilder.Entity<MetadataID<Show>>().HasOne(x => x.Second).WithMany()
|
|
||||||
.OnDelete(DeleteBehavior.Cascade);
|
|
||||||
|
|
||||||
|
_HasMetadata<Collection>(modelBuilder);
|
||||||
|
_HasMetadata<Show>(modelBuilder);
|
||||||
|
_HasMetadata<Season>(modelBuilder);
|
||||||
|
_HasMetadata<Episode>(modelBuilder);
|
||||||
|
_HasMetadata<People>(modelBuilder);
|
||||||
|
_HasMetadata<Studio>(modelBuilder);
|
||||||
|
|
||||||
modelBuilder.Entity<WatchedEpisode>()
|
modelBuilder.Entity<WatchedEpisode>()
|
||||||
.HasKey(x => new {First = x.FirstID, Second = x.SecondID});
|
.HasKey(x => new {First = x.FirstID, Second = x.SecondID});
|
||||||
|
|
||||||
|
@ -22,9 +22,9 @@ namespace Kyoo.Tests
|
|||||||
|
|
||||||
ProviderRepository provider = new(_database);
|
ProviderRepository provider = new(_database);
|
||||||
LibraryRepository library = new(_database, provider);
|
LibraryRepository library = new(_database, provider);
|
||||||
CollectionRepository collection = new(_database);
|
CollectionRepository collection = new(_database, provider);
|
||||||
GenreRepository genre = new(_database);
|
GenreRepository genre = new(_database);
|
||||||
StudioRepository studio = new(_database);
|
StudioRepository studio = new(_database, provider);
|
||||||
PeopleRepository people = new(_database, provider,
|
PeopleRepository people = new(_database, provider,
|
||||||
new Lazy<IShowRepository>(() => LibraryManager.ShowRepository));
|
new Lazy<IShowRepository>(() => LibraryManager.ShowRepository));
|
||||||
ShowRepository show = new(_database, studio, people, genre, provider);
|
ShowRepository show = new(_database, studio, people, genre, provider);
|
||||||
|
@ -149,10 +149,9 @@ namespace Kyoo.Tests.Database
|
|||||||
Show value = await _repository.Get(TestSample.Get<Show>().Slug);
|
Show value = await _repository.Get(TestSample.Get<Show>().Slug);
|
||||||
value.ExternalIDs = new[]
|
value.ExternalIDs = new[]
|
||||||
{
|
{
|
||||||
new MetadataID<Show>()
|
new MetadataID
|
||||||
{
|
{
|
||||||
First = value,
|
Provider = new Provider("test", "test.png"),
|
||||||
Second = new Provider("test", "test.png"),
|
|
||||||
DataID = "1234"
|
DataID = "1234"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -160,19 +159,19 @@ namespace Kyoo.Tests.Database
|
|||||||
|
|
||||||
Assert.Equal(value.Slug, edited.Slug);
|
Assert.Equal(value.Slug, edited.Slug);
|
||||||
Assert.Equal(
|
Assert.Equal(
|
||||||
value.ExternalIDs.Select(x => new {x.DataID, x.Second.Slug}),
|
value.ExternalIDs.Select(x => new {x.DataID, x.Provider.Slug}),
|
||||||
edited.ExternalIDs.Select(x => new {x.DataID, x.Second.Slug}));
|
edited.ExternalIDs.Select(x => new {x.DataID, x.Provider.Slug}));
|
||||||
|
|
||||||
await using DatabaseContext database = Repositories.Context.New();
|
await using DatabaseContext database = Repositories.Context.New();
|
||||||
Show show = await database.Shows
|
Show show = await database.Shows
|
||||||
.Include(x => x.ExternalIDs)
|
.Include(x => x.ExternalIDs)
|
||||||
.ThenInclude(x => x.Second)
|
.ThenInclude(x => x.Provider)
|
||||||
.FirstAsync();
|
.FirstAsync();
|
||||||
|
|
||||||
Assert.Equal(value.Slug, show.Slug);
|
Assert.Equal(value.Slug, show.Slug);
|
||||||
Assert.Equal(
|
Assert.Equal(
|
||||||
value.ExternalIDs.Select(x => new {x.DataID, x.Second.Slug}),
|
value.ExternalIDs.Select(x => new {x.DataID, x.Provider.Slug}),
|
||||||
show.ExternalIDs.Select(x => new {x.DataID, x.Second.Slug}));
|
show.ExternalIDs.Select(x => new {x.DataID, x.Provider.Slug}));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@ -209,10 +208,9 @@ namespace Kyoo.Tests.Database
|
|||||||
expected.Slug = "created-relation-test";
|
expected.Slug = "created-relation-test";
|
||||||
expected.ExternalIDs = new[]
|
expected.ExternalIDs = new[]
|
||||||
{
|
{
|
||||||
new MetadataID<Show>
|
new MetadataID
|
||||||
{
|
{
|
||||||
First = expected,
|
Provider = new Provider("provider", "provider.png"),
|
||||||
Second = new Provider("provider", "provider.png"),
|
|
||||||
DataID = "ID"
|
DataID = "ID"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -48,9 +48,9 @@ namespace Kyoo.TheMovieDb
|
|||||||
.ToArray(),
|
.ToArray(),
|
||||||
ExternalIDs = new []
|
ExternalIDs = new []
|
||||||
{
|
{
|
||||||
new MetadataID<Show>
|
new MetadataID
|
||||||
{
|
{
|
||||||
Second = provider,
|
Provider = provider,
|
||||||
Link = $"https://www.themoviedb.org/movie/{movie.Id}",
|
Link = $"https://www.themoviedb.org/movie/{movie.Id}",
|
||||||
DataID = movie.Id.ToString()
|
DataID = movie.Id.ToString()
|
||||||
}
|
}
|
||||||
@ -94,9 +94,9 @@ namespace Kyoo.TheMovieDb
|
|||||||
.ToArray(),
|
.ToArray(),
|
||||||
ExternalIDs = new []
|
ExternalIDs = new []
|
||||||
{
|
{
|
||||||
new MetadataID<Show>
|
new MetadataID
|
||||||
{
|
{
|
||||||
Second = provider,
|
Provider = provider,
|
||||||
Link = $"https://www.themoviedb.org/movie/{tv.Id}",
|
Link = $"https://www.themoviedb.org/movie/{tv.Id}",
|
||||||
DataID = tv.Id.ToString()
|
DataID = tv.Id.ToString()
|
||||||
}
|
}
|
||||||
@ -145,9 +145,9 @@ namespace Kyoo.TheMovieDb
|
|||||||
IsMovie = true,
|
IsMovie = true,
|
||||||
ExternalIDs = new []
|
ExternalIDs = new []
|
||||||
{
|
{
|
||||||
new MetadataID<Show>
|
new MetadataID
|
||||||
{
|
{
|
||||||
Second = provider,
|
Provider = provider,
|
||||||
Link = $"https://www.themoviedb.org/movie/{movie.Id}",
|
Link = $"https://www.themoviedb.org/movie/{movie.Id}",
|
||||||
DataID = movie.Id.ToString()
|
DataID = movie.Id.ToString()
|
||||||
}
|
}
|
||||||
@ -178,9 +178,9 @@ namespace Kyoo.TheMovieDb
|
|||||||
IsMovie = true,
|
IsMovie = true,
|
||||||
ExternalIDs = new []
|
ExternalIDs = new []
|
||||||
{
|
{
|
||||||
new MetadataID<Show>
|
new MetadataID
|
||||||
{
|
{
|
||||||
Second = provider,
|
Provider = provider,
|
||||||
Link = $"https://www.themoviedb.org/movie/{tv.Id}",
|
Link = $"https://www.themoviedb.org/movie/{tv.Id}",
|
||||||
DataID = tv.Id.ToString()
|
DataID = tv.Id.ToString()
|
||||||
}
|
}
|
||||||
@ -205,9 +205,9 @@ namespace Kyoo.TheMovieDb
|
|||||||
Poster = cast.ProfilePath != null ? $"https://image.tmdb.org/t/p/original{cast.ProfilePath}" : null,
|
Poster = cast.ProfilePath != null ? $"https://image.tmdb.org/t/p/original{cast.ProfilePath}" : null,
|
||||||
ExternalIDs = new[]
|
ExternalIDs = new[]
|
||||||
{
|
{
|
||||||
new MetadataID<People>
|
new MetadataID
|
||||||
{
|
{
|
||||||
Second = provider,
|
Provider = provider,
|
||||||
DataID = cast.Id.ToString(),
|
DataID = cast.Id.ToString(),
|
||||||
Link = $"https://www.themoviedb.org/person/{cast.Id}"
|
Link = $"https://www.themoviedb.org/person/{cast.Id}"
|
||||||
}
|
}
|
||||||
@ -235,9 +235,9 @@ namespace Kyoo.TheMovieDb
|
|||||||
Poster = cast.ProfilePath != null ? $"https://image.tmdb.org/t/p/original{cast.ProfilePath}" : null,
|
Poster = cast.ProfilePath != null ? $"https://image.tmdb.org/t/p/original{cast.ProfilePath}" : null,
|
||||||
ExternalIDs = new[]
|
ExternalIDs = new[]
|
||||||
{
|
{
|
||||||
new MetadataID<People>
|
new MetadataID
|
||||||
{
|
{
|
||||||
Second = provider,
|
Provider = provider,
|
||||||
DataID = cast.Id.ToString(),
|
DataID = cast.Id.ToString(),
|
||||||
Link = $"https://www.themoviedb.org/person/{cast.Id}"
|
Link = $"https://www.themoviedb.org/person/{cast.Id}"
|
||||||
}
|
}
|
||||||
@ -265,9 +265,9 @@ namespace Kyoo.TheMovieDb
|
|||||||
Poster = crew.ProfilePath != null ? $"https://image.tmdb.org/t/p/original{crew.ProfilePath}" : null,
|
Poster = crew.ProfilePath != null ? $"https://image.tmdb.org/t/p/original{crew.ProfilePath}" : null,
|
||||||
ExternalIDs = new[]
|
ExternalIDs = new[]
|
||||||
{
|
{
|
||||||
new MetadataID<People>
|
new MetadataID
|
||||||
{
|
{
|
||||||
Second = provider,
|
Provider = provider,
|
||||||
DataID = crew.Id.ToString(),
|
DataID = crew.Id.ToString(),
|
||||||
Link = $"https://www.themoviedb.org/person/{crew.Id}"
|
Link = $"https://www.themoviedb.org/person/{crew.Id}"
|
||||||
}
|
}
|
||||||
|
@ -58,11 +58,11 @@ namespace Kyoo.TheTvdb
|
|||||||
Poster = result.Poster != null ? $"https://www.thetvdb.com{result.Poster}" : null,
|
Poster = result.Poster != null ? $"https://www.thetvdb.com{result.Poster}" : null,
|
||||||
ExternalIDs = new[]
|
ExternalIDs = new[]
|
||||||
{
|
{
|
||||||
new MetadataID<Show>
|
new MetadataID
|
||||||
{
|
{
|
||||||
DataID = result.Id.ToString(),
|
DataID = result.Id.ToString(),
|
||||||
Link = $"https://www.thetvdb.com/series/{result.Slug}",
|
Link = $"https://www.thetvdb.com/series/{result.Slug}",
|
||||||
Second = provider
|
Provider = provider
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -89,11 +89,11 @@ namespace Kyoo.TheTvdb
|
|||||||
Genres = series.Genre.Select(y => new Genre(y)).ToList(),
|
Genres = series.Genre.Select(y => new Genre(y)).ToList(),
|
||||||
ExternalIDs = new[]
|
ExternalIDs = new[]
|
||||||
{
|
{
|
||||||
new MetadataID<Show>
|
new MetadataID
|
||||||
{
|
{
|
||||||
DataID = series.Id.ToString(),
|
DataID = series.Id.ToString(),
|
||||||
Link = $"https://www.thetvdb.com/series/{series.Slug}",
|
Link = $"https://www.thetvdb.com/series/{series.Slug}",
|
||||||
Second = provider
|
Provider = provider
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -116,11 +116,11 @@ namespace Kyoo.TheTvdb
|
|||||||
Poster = actor.Image != null ? $"https://www.thetvdb.com/banners/{actor.Image}" : null,
|
Poster = actor.Image != null ? $"https://www.thetvdb.com/banners/{actor.Image}" : null,
|
||||||
ExternalIDs = new []
|
ExternalIDs = new []
|
||||||
{
|
{
|
||||||
new MetadataID<People>()
|
new MetadataID
|
||||||
{
|
{
|
||||||
DataID = actor.Id.ToString(),
|
DataID = actor.Id.ToString(),
|
||||||
Link = $"https://www.thetvdb.com/people/{actor.Id}",
|
Link = $"https://www.thetvdb.com/people/{actor.Id}",
|
||||||
Second = provider
|
Provider = provider
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -147,11 +147,11 @@ namespace Kyoo.TheTvdb
|
|||||||
Thumb = episode.Filename != null ? $"https://www.thetvdb.com/banners/{episode.Filename}" : null,
|
Thumb = episode.Filename != null ? $"https://www.thetvdb.com/banners/{episode.Filename}" : null,
|
||||||
ExternalIDs = new[]
|
ExternalIDs = new[]
|
||||||
{
|
{
|
||||||
new MetadataID<Episode>
|
new MetadataID
|
||||||
{
|
{
|
||||||
DataID = episode.Id.ToString(),
|
DataID = episode.Id.ToString(),
|
||||||
Link = $"https://www.thetvdb.com/series/{episode.SeriesId}/episodes/{episode.Id}",
|
Link = $"https://www.thetvdb.com/series/{episode.SeriesId}/episodes/{episode.Id}",
|
||||||
Second = provider
|
Provider = provider
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -18,6 +18,11 @@ namespace Kyoo.Controllers
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly DatabaseContext _database;
|
private readonly DatabaseContext _database;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A provider repository to handle externalID creation and deletion
|
||||||
|
/// </summary>
|
||||||
|
private readonly IProviderRepository _providers;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override Expression<Func<Collection, object>> DefaultSort => x => x.Name;
|
protected override Expression<Func<Collection, object>> DefaultSort => x => x.Name;
|
||||||
|
|
||||||
@ -25,10 +30,12 @@ namespace Kyoo.Controllers
|
|||||||
/// Create a new <see cref="CollectionRepository"/>.
|
/// Create a new <see cref="CollectionRepository"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="database">The database handle to use</param>
|
/// <param name="database">The database handle to use</param>
|
||||||
public CollectionRepository(DatabaseContext database)
|
/// /// <param name="providers">A provider repository</param>
|
||||||
|
public CollectionRepository(DatabaseContext database, IProviderRepository providers)
|
||||||
: base(database)
|
: base(database)
|
||||||
{
|
{
|
||||||
_database = database;
|
_database = database;
|
||||||
|
_providers = providers;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -46,9 +53,35 @@ namespace Kyoo.Controllers
|
|||||||
{
|
{
|
||||||
await base.Create(obj);
|
await base.Create(obj);
|
||||||
_database.Entry(obj).State = EntityState.Added;
|
_database.Entry(obj).State = EntityState.Added;
|
||||||
|
obj.ExternalIDs.ForEach(x => _database.Entry(x).State = EntityState.Added);
|
||||||
await _database.SaveChangesAsync($"Trying to insert a duplicated collection (slug {obj.Slug} already exists).");
|
await _database.SaveChangesAsync($"Trying to insert a duplicated collection (slug {obj.Slug} already exists).");
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override async Task Validate(Collection resource)
|
||||||
|
{
|
||||||
|
await base.Validate(resource);
|
||||||
|
await resource.ExternalIDs.ForEachAsync(async x =>
|
||||||
|
{
|
||||||
|
x.Provider = await _providers.CreateIfNotExists(x.Provider);
|
||||||
|
x.ProviderID = x.Provider.ID;
|
||||||
|
x.ResourceType = nameof(Collection);
|
||||||
|
_database.Entry(x.Provider).State = EntityState.Detached;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override async Task EditRelations(Collection resource, Collection changed, bool resetOld)
|
||||||
|
{
|
||||||
|
if (changed.ExternalIDs != null || resetOld)
|
||||||
|
{
|
||||||
|
await Database.Entry(resource).Collection(x => x.ExternalIDs).LoadAsync();
|
||||||
|
resource.ExternalIDs = changed.ExternalIDs;
|
||||||
|
}
|
||||||
|
|
||||||
|
await base.EditRelations(resource, changed, resetOld);
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override async Task Delete(Collection obj)
|
public override async Task Delete(Collection obj)
|
||||||
|
@ -160,9 +160,10 @@ namespace Kyoo.Controllers
|
|||||||
await base.Validate(resource);
|
await base.Validate(resource);
|
||||||
await resource.ExternalIDs.ForEachAsync(async x =>
|
await resource.ExternalIDs.ForEachAsync(async x =>
|
||||||
{
|
{
|
||||||
x.Second = await _providers.CreateIfNotExists(x.Second);
|
x.Provider = await _providers.CreateIfNotExists(x.Provider);
|
||||||
x.SecondID = x.Second.ID;
|
x.ProviderID = x.Provider.ID;
|
||||||
_database.Entry(x.Second).State = EntityState.Detached;
|
x.ResourceType = nameof(Episode);
|
||||||
|
_database.Entry(x.Provider).State = EntityState.Detached;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,9 +73,10 @@ namespace Kyoo.Controllers
|
|||||||
await base.Validate(resource);
|
await base.Validate(resource);
|
||||||
await resource.ExternalIDs.ForEachAsync(async id =>
|
await resource.ExternalIDs.ForEachAsync(async id =>
|
||||||
{
|
{
|
||||||
id.Second = await _providers.CreateIfNotExists(id.Second);
|
id.Provider = await _providers.CreateIfNotExists(id.Provider);
|
||||||
id.SecondID = id.Second.ID;
|
id.ProviderID = id.Provider.ID;
|
||||||
_database.Entry(id.Second).State = EntityState.Detached;
|
id.ResourceType = nameof(People);
|
||||||
|
_database.Entry(id.Provider).State = EntityState.Detached;
|
||||||
});
|
});
|
||||||
await resource.Roles.ForEachAsync(async role =>
|
await resource.Roles.ForEachAsync(async role =>
|
||||||
{
|
{
|
||||||
|
@ -9,21 +9,18 @@ using Microsoft.EntityFrameworkCore;
|
|||||||
namespace Kyoo.Controllers
|
namespace Kyoo.Controllers
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A local repository to handle providers.
|
/// A local repository to handle providers.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ProviderRepository : LocalRepository<Provider>, IProviderRepository
|
public class ProviderRepository : LocalRepository<Provider>, IProviderRepository
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The database handle
|
/// The database handle
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly DatabaseContext _database;
|
private readonly DatabaseContext _database;
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
protected override Expression<Func<Provider, object>> DefaultSort => x => x.Slug;
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a new <see cref="ProviderRepository"/>.
|
/// Create a new <see cref="ProviderRepository" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="database">The database handle</param>
|
/// <param name="database">The database handle</param>
|
||||||
public ProviderRepository(DatabaseContext database)
|
public ProviderRepository(DatabaseContext database)
|
||||||
@ -32,6 +29,9 @@ namespace Kyoo.Controllers
|
|||||||
_database = database;
|
_database = database;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override Expression<Func<Provider, object>> DefaultSort => x => x.Slug;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override async Task<ICollection<Provider>> Search(string query)
|
public override async Task<ICollection<Provider>> Search(string query)
|
||||||
{
|
{
|
||||||
@ -47,7 +47,8 @@ namespace Kyoo.Controllers
|
|||||||
{
|
{
|
||||||
await base.Create(obj);
|
await base.Create(obj);
|
||||||
_database.Entry(obj).State = EntityState.Added;
|
_database.Entry(obj).State = EntityState.Added;
|
||||||
await _database.SaveChangesAsync($"Trying to insert a duplicated provider (slug {obj.Slug} already exists).");
|
await _database.SaveChangesAsync("Trying to insert a duplicated provider " +
|
||||||
|
$"(slug {obj.Slug} already exists).");
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,20 +57,24 @@ namespace Kyoo.Controllers
|
|||||||
{
|
{
|
||||||
if (obj == null)
|
if (obj == null)
|
||||||
throw new ArgumentNullException(nameof(obj));
|
throw new ArgumentNullException(nameof(obj));
|
||||||
|
|
||||||
_database.Entry(obj).State = EntityState.Deleted;
|
_database.Entry(obj).State = EntityState.Deleted;
|
||||||
await _database.SaveChangesAsync();
|
await _database.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public Task<ICollection<MetadataID<T>>> GetMetadataID<T>(Expression<Func<MetadataID<T>, bool>> where = null,
|
public Task<ICollection<MetadataID>> GetMetadataID<T>(Expression<Func<MetadataID, bool>> where = null,
|
||||||
Sort<MetadataID<T>> sort = default,
|
Sort<MetadataID> sort = default,
|
||||||
Pagination limit = default)
|
Pagination limit = default)
|
||||||
where T : class, IResource
|
where T : class, IMetadata
|
||||||
{
|
{
|
||||||
return ApplyFilters(_database.MetadataIds<T>().Include(y => y.Second),
|
string discriminator = typeof(T).Name;
|
||||||
x => _database.MetadataIds<T>().FirstOrDefaultAsync(y => y.FirstID == x),
|
return ApplyFilters(_database.MetadataIDs
|
||||||
x => x.FirstID,
|
.Include(y => y.Provider)
|
||||||
|
.Where(x => x.ResourceType == discriminator),
|
||||||
|
x => _database.MetadataIDs.FirstOrDefaultAsync(y => y.ResourceID == x
|
||||||
|
&& y.ResourceType == discriminator),
|
||||||
|
x => x.ResourceID,
|
||||||
where,
|
where,
|
||||||
sort,
|
sort,
|
||||||
limit);
|
limit);
|
||||||
|
@ -106,9 +106,10 @@ namespace Kyoo.Controllers
|
|||||||
await base.Validate(resource);
|
await base.Validate(resource);
|
||||||
await resource.ExternalIDs.ForEachAsync(async id =>
|
await resource.ExternalIDs.ForEachAsync(async id =>
|
||||||
{
|
{
|
||||||
id.Second = await _providers.CreateIfNotExists(id.Second);
|
id.Provider = await _providers.CreateIfNotExists(id.Provider);
|
||||||
id.SecondID = id.Second.ID;
|
id.ProviderID = id.Provider.ID;
|
||||||
_database.Entry(id.Second).State = EntityState.Detached;
|
id.ResourceType = nameof(Season);
|
||||||
|
_database.Entry(id.Provider).State = EntityState.Detached;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,9 +101,10 @@ namespace Kyoo.Controllers
|
|||||||
});
|
});
|
||||||
await resource.ExternalIDs.ForEachAsync(async id =>
|
await resource.ExternalIDs.ForEachAsync(async id =>
|
||||||
{
|
{
|
||||||
id.Second = await _providers.CreateIfNotExists(id.Second);
|
id.Provider = await _providers.CreateIfNotExists(id.Provider);
|
||||||
id.SecondID = id.Second.ID;
|
id.ProviderID = id.Provider.ID;
|
||||||
_database.Entry(id.Second).State = EntityState.Detached;
|
id.ResourceType = nameof(Show);
|
||||||
|
_database.Entry(id.Provider).State = EntityState.Detached;
|
||||||
});
|
});
|
||||||
await resource.People.ForEachAsync(async role =>
|
await resource.People.ForEachAsync(async role =>
|
||||||
{
|
{
|
||||||
|
@ -18,6 +18,11 @@ namespace Kyoo.Controllers
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly DatabaseContext _database;
|
private readonly DatabaseContext _database;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A provider repository to handle externalID creation and deletion
|
||||||
|
/// </summary>
|
||||||
|
private readonly IProviderRepository _providers;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override Expression<Func<Studio, object>> DefaultSort => x => x.Name;
|
protected override Expression<Func<Studio, object>> DefaultSort => x => x.Name;
|
||||||
|
|
||||||
@ -26,10 +31,12 @@ namespace Kyoo.Controllers
|
|||||||
/// Create a new <see cref="StudioRepository"/>.
|
/// Create a new <see cref="StudioRepository"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="database">The database handle</param>
|
/// <param name="database">The database handle</param>
|
||||||
public StudioRepository(DatabaseContext database)
|
/// <param name="providers">A provider repository</param>
|
||||||
|
public StudioRepository(DatabaseContext database, IProviderRepository providers)
|
||||||
: base(database)
|
: base(database)
|
||||||
{
|
{
|
||||||
_database = database;
|
_database = database;
|
||||||
|
_providers = providers;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -50,6 +57,31 @@ namespace Kyoo.Controllers
|
|||||||
await _database.SaveChangesAsync($"Trying to insert a duplicated studio (slug {obj.Slug} already exists).");
|
await _database.SaveChangesAsync($"Trying to insert a duplicated studio (slug {obj.Slug} already exists).");
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override async Task Validate(Studio resource)
|
||||||
|
{
|
||||||
|
await base.Validate(resource);
|
||||||
|
await resource.ExternalIDs.ForEachAsync(async x =>
|
||||||
|
{
|
||||||
|
x.Provider = await _providers.CreateIfNotExists(x.Provider);
|
||||||
|
x.ProviderID = x.Provider.ID;
|
||||||
|
x.ResourceType = nameof(Studio);
|
||||||
|
_database.Entry(x.Provider).State = EntityState.Detached;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override async Task EditRelations(Studio resource, Studio changed, bool resetOld)
|
||||||
|
{
|
||||||
|
if (changed.ExternalIDs != null || resetOld)
|
||||||
|
{
|
||||||
|
await Database.Entry(resource).Collection(x => x.ExternalIDs).LoadAsync();
|
||||||
|
resource.ExternalIDs = changed.ExternalIDs;
|
||||||
|
}
|
||||||
|
|
||||||
|
await base.EditRelations(resource, changed, resetOld);
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override async Task Delete(Studio obj)
|
public override async Task Delete(Studio obj)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user