diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 65a3646f..7c86b7b0 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -24,7 +24,7 @@ jobs:
- name: Build
run: |
dotnet build --no-restore '-p:SkipWebApp=true;SkipTranscoder=true' -p:CopyLocalLockFileAssemblies=true
- cp ./Kyoo.Common/bin/Debug/net5.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll ./Kyoo.Tests/bin/Debug/net5.0/
+ cp ./Kyoo.Common/bin/Debug/net5.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll ./tests/Kyoo.Tests/bin/Debug/net5.0/
- name: Test
run: dotnet test --no-build '-p:CollectCoverage=true;CoverletOutputFormat=opencover'
env:
@@ -33,7 +33,7 @@ jobs:
POSTGRES_PASSWORD: postgres
- name: Sanitize coverage output
if: ${{ always() }}
- run: sed -i "s'$(pwd)'.'" Kyoo.Tests/coverage.opencover.xml
+ run: sed -i "s'$(pwd)'.'" tests/Kyoo.Tests/coverage.opencover.xml
- name: Upload coverage report
if: ${{ always() }}
uses: actions/upload-artifact@v2
diff --git a/Kyoo.Common/Controllers/IFileSystem.cs b/Kyoo.Common/Controllers/IFileSystem.cs
index 2fb1c6d7..92e951b7 100644
--- a/Kyoo.Common/Controllers/IFileSystem.cs
+++ b/Kyoo.Common/Controllers/IFileSystem.cs
@@ -2,11 +2,25 @@ using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using JetBrains.Annotations;
-using Kyoo.Models;
using Microsoft.AspNetCore.Mvc;
namespace Kyoo.Controllers
{
+ ///
+ /// A class wrapping a value that will be set after the completion of the task it is related to.
+ ///
+ ///
+ /// This class replace the use of an out parameter on a task since tasks and out can't be combined.
+ ///
+ /// The type of the value
+ public class AsyncRef
+ {
+ ///
+ /// The value that will be set before the completion of the task.
+ ///
+ public T Value { get; set; }
+ }
+
///
/// A service to abstract the file system to allow custom file systems (like distant file systems or external providers)
///
@@ -42,6 +56,16 @@ namespace Kyoo.Controllers
/// If the file could not be found.
/// A reader to read the file.
public Task GetReader([NotNull] string path);
+
+ ///
+ /// Read a file present at . The reader can be used in an arbitrary context.
+ /// To return files from an http endpoint, use .
+ ///
+ /// The path of the file
+ /// The mime type of the opened file.
+ /// If the file could not be found.
+ /// A reader to read the file.
+ public Task GetReader([NotNull] string path, AsyncRef mime);
///
/// Create a new file at .
@@ -81,12 +105,13 @@ namespace Kyoo.Controllers
public Task Exists([NotNull] string path);
///
- /// Get the extra directory of a show.
+ /// Get the extra directory of a resource .
/// This method is in this system to allow a filesystem to use a different metadata policy for one.
/// It can be useful if the filesystem is readonly.
///
- /// The show to proceed
- /// The extra directory of the show
- public string GetExtraDirectory([NotNull] Show show);
+ /// The resource to proceed
+ /// The type of the resource.
+ /// The extra directory of the resource.
+ public Task GetExtraDirectory([NotNull] T resource);
}
}
\ No newline at end of file
diff --git a/Kyoo.Common/Controllers/ILibraryManager.cs b/Kyoo.Common/Controllers/ILibraryManager.cs
index 938d3029..8c3442e3 100644
--- a/Kyoo.Common/Controllers/ILibraryManager.cs
+++ b/Kyoo.Common/Controllers/ILibraryManager.cs
@@ -225,42 +225,51 @@ namespace Kyoo.Controllers
///
/// The source object.
/// A getter function for the member to load
+ ///
+ /// true if you want to load the relation even if it is not null, false otherwise.
+ ///
/// The type of the source object
/// The related resource's type
/// The param
- ///
- ///
- ///
- Task Load([NotNull] T obj, Expression> member)
+ ///
+ ///
+ ///
+ Task Load([NotNull] T obj, Expression> member, bool force = false)
where T : class, IResource
- where T2 : class, IResource, new();
+ where T2 : class, IResource;
///
/// Load a collection of related resource
///
/// The source object.
/// A getter function for the member to load
+ ///
+ /// true if you want to load the relation even if it is not null, false otherwise.
+ ///
/// The type of the source object
/// The related resource's type
/// The param
- ///
- ///
- ///
- Task Load([NotNull] T obj, Expression>> member)
+ ///
+ ///
+ ///
+ Task Load([NotNull] T obj, Expression>> member, bool force = false)
where T : class, IResource
- where T2 : class, new();
+ where T2 : class;
///
/// Load a related resource by it's name
///
/// The source object.
/// The name of the resource to load (case sensitive)
+ ///
+ /// true if you want to load the relation even if it is not null, false otherwise.
+ ///
/// The type of the source object
/// The param
- ///
- ///
- ///
- Task Load([NotNull] T obj, string memberName)
+ ///
+ ///
+ ///
+ Task Load([NotNull] T obj, string memberName, bool force = false)
where T : class, IResource;
///
@@ -268,10 +277,13 @@ namespace Kyoo.Controllers
///
/// The source object.
/// The name of the resource to load (case sensitive)
- ///
- ///
- ///
- Task Load([NotNull] IResource obj, string memberName);
+ ///
+ /// true if you want to load the relation even if it is not null, false otherwise.
+ ///
+ ///
+ ///
+ ///
+ Task Load([NotNull] IResource obj, string memberName, bool force = false);
///
/// Get items (A wrapper arround shows or collections) from a library.
diff --git a/Kyoo.Common/Controllers/IRepository.cs b/Kyoo.Common/Controllers/IRepository.cs
index a83d17fa..c5fe7a7c 100644
--- a/Kyoo.Common/Controllers/IRepository.cs
+++ b/Kyoo.Common/Controllers/IRepository.cs
@@ -590,10 +590,10 @@ namespace Kyoo.Controllers
/// Pagination information (where to start and how many to get)
/// The type of metadata to retrieve
/// A filtered list of external ids.
- Task>> GetMetadataID(Expression, bool>> where = null,
- Sort> sort = default,
+ Task> GetMetadataID(Expression> where = null,
+ Sort sort = default,
Pagination limit = default)
- where T : class, IResource;
+ where T : class, IMetadata;
///
/// Get a list of external ids that match all filters
@@ -602,11 +602,11 @@ namespace Kyoo.Controllers
/// A sort by expression
/// Pagination information (where to start and how many to get)
/// A filtered list of external ids.
- Task>> GetMetadataID([Optional] Expression, bool>> where,
- Expression, object>> sort,
+ Task> GetMetadataID([Optional] Expression> where,
+ Expression> sort,
Pagination limit = default
- ) where T : class, IResource
- => GetMetadataID(where, new Sort>(sort), limit);
+ ) where T : class, IMetadata
+ => GetMetadataID(where, new Sort(sort), limit);
}
///
diff --git a/Kyoo.Common/Controllers/IThumbnailsManager.cs b/Kyoo.Common/Controllers/IThumbnailsManager.cs
index 465d4c62..61fe5345 100644
--- a/Kyoo.Common/Controllers/IThumbnailsManager.cs
+++ b/Kyoo.Common/Controllers/IThumbnailsManager.cs
@@ -1,5 +1,4 @@
-using System;
-using Kyoo.Models;
+using Kyoo.Models;
using System.Threading.Tasks;
using JetBrains.Annotations;
@@ -23,37 +22,17 @@ namespace Kyoo.Controllers
/// The type of the item
/// true if an image has been downloaded, false otherwise.
Task DownloadImages([NotNull] T item, bool alwaysDownload = false)
- where T : IResource;
-
+ where T : IThumbnails;
+
///
- /// Retrieve the local path of the poster of the given item.
+ /// Retrieve the local path of an image of the given item.
///
/// The item to retrieve the poster from.
+ /// The ID of the image. See for values.
/// The type of the item
- /// If the type does not have a poster
- /// The path of the poster for the given resource (it might or might not exists).
- Task GetPoster([NotNull] T item)
- where T : IResource;
-
- ///
- /// Retrieve the local path of the logo of the given item.
- ///
- /// The item to retrieve the logo from.
- /// The type of the item
- /// If the type does not have a logo
- /// The path of the logo for the given resource (it might or might not exists).
- Task GetLogo([NotNull] T item)
- where T : IResource;
-
- ///
- /// Retrieve the local path of the thumbnail of the given item.
- ///
- /// The item to retrieve the thumbnail from.
- /// The type of the item
- /// If the type does not have a thumbnail
- /// The path of the thumbnail for the given resource (it might or might not exists).
- Task GetThumbnail([NotNull] T item)
- where T : IResource;
+ /// The path of the image for the given resource or null if it does not exists.
+ Task GetImagePath([NotNull] T item, int imageID)
+ where T : IThumbnails;
}
}
diff --git a/Kyoo.Common/Controllers/Implementations/LibraryManager.cs b/Kyoo.Common/Controllers/Implementations/LibraryManager.cs
index 12ea0b2a..08475c32 100644
--- a/Kyoo.Common/Controllers/Implementations/LibraryManager.cs
+++ b/Kyoo.Common/Controllers/Implementations/LibraryManager.cs
@@ -162,34 +162,6 @@ namespace Kyoo.Controllers
return await EpisodeRepository.GetOrDefault(showSlug, seasonNumber, episodeNumber);
}
- ///
- public Task Load(T obj, Expression> member)
- where T : class, IResource
- where T2 : class, IResource, new()
- {
- if (member == null)
- throw new ArgumentNullException(nameof(member));
- return Load(obj, Utility.GetPropertyName(member));
- }
-
- ///
- public Task Load(T obj, Expression>> member)
- where T : class, IResource
- where T2 : class, new()
- {
- if (member == null)
- throw new ArgumentNullException(nameof(member));
- return Load(obj, Utility.GetPropertyName(member));
- }
-
- ///
- public async Task Load(T obj, string memberName)
- where T : class, IResource
- {
- await Load(obj as IResource, memberName);
- return obj;
- }
-
///
/// Set relations between to objects.
///
@@ -211,11 +183,46 @@ namespace Kyoo.Controllers
}
///
- public Task Load(IResource obj, string memberName)
+ public Task Load(T obj, Expression> member, bool force = false)
+ where T : class, IResource
+ where T2 : class, IResource
+ {
+ if (member == null)
+ throw new ArgumentNullException(nameof(member));
+ return Load(obj, Utility.GetPropertyName(member), force);
+ }
+
+ ///
+ public Task Load(T obj, Expression>> member, bool force = false)
+ where T : class, IResource
+ where T2 : class
+ {
+ if (member == null)
+ throw new ArgumentNullException(nameof(member));
+ return Load(obj, Utility.GetPropertyName(member), force);
+ }
+
+ ///
+ public async Task Load(T obj, string memberName, bool force = false)
+ where T : class, IResource
+ {
+ await Load(obj as IResource, memberName, force);
+ return obj;
+ }
+
+ ///
+ public Task Load(IResource obj, string memberName, bool force = false)
{
if (obj == null)
throw new ArgumentNullException(nameof(obj));
-
+
+ object existingValue = obj.GetType()
+ .GetProperties()
+ .FirstOrDefault(x => string.Equals(x.Name, memberName, StringComparison.InvariantCultureIgnoreCase))
+ ?.GetValue(obj);
+ if (existingValue != null && !force)
+ return Task.CompletedTask;
+
return (obj, member: memberName) switch
{
(Library l, nameof(Library.Providers)) => ProviderRepository
@@ -231,7 +238,12 @@ namespace Kyoo.Controllers
.Then(x => l.Collections = x),
- (Collection c, nameof(Library.Shows)) => ShowRepository
+ (Collection c, nameof(Collection.ExternalIDs)) => SetRelation(c,
+ ProviderRepository.GetMetadataID(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))
.Then(x => c.Shows = x),
@@ -241,9 +253,9 @@ namespace Kyoo.Controllers
(Show s, nameof(Show.ExternalIDs)) => SetRelation(s,
- ProviderRepository.GetMetadataID(x => x.FirstID == obj.ID),
+ ProviderRepository.GetMetadataID(x => x.ResourceID == obj.ID),
(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
.GetAll(x => x.Shows.Any(y => y.ID == obj.ID))
@@ -281,9 +293,9 @@ namespace Kyoo.Controllers
(Season s, nameof(Season.ExternalIDs)) => SetRelation(s,
- ProviderRepository.GetMetadataID(x => x.FirstID == obj.ID),
+ ProviderRepository.GetMetadataID(x => x.ResourceID == obj.ID),
(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,
EpisodeRepository.GetAll(x => x.Season.ID == obj.ID),
@@ -300,9 +312,9 @@ namespace Kyoo.Controllers
(Episode e, nameof(Episode.ExternalIDs)) => SetRelation(e,
- ProviderRepository.GetMetadataID(x => x.FirstID == obj.ID),
+ ProviderRepository.GetMetadataID(x => x.ResourceID == obj.ID),
(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,
TrackRepository.GetAll(x => x.Episode.ID == obj.ID),
@@ -344,11 +356,16 @@ namespace Kyoo.Controllers
.GetAll(x => x.Studio.ID == obj.ID)
.Then(x => s.Shows = x),
+ (Studio s, nameof(Studio.ExternalIDs)) => SetRelation(s,
+ ProviderRepository.GetMetadataID(x => x.ResourceID == obj.ID),
+ (x, y) => x.ExternalIDs = y,
+ (x, y) => { x.ResourceID = y.ID; }),
+
(People p, nameof(People.ExternalIDs)) => SetRelation(p,
- ProviderRepository.GetMetadataID(x => x.FirstID == obj.ID),
+ ProviderRepository.GetMetadataID(x => x.ResourceID == obj.ID),
(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
.GetFromPeople(obj.ID)
diff --git a/Kyoo.Common/Kyoo.Common.csproj b/Kyoo.Common/Kyoo.Common.csproj
index 844be997..ec328eab 100644
--- a/Kyoo.Common/Kyoo.Common.csproj
+++ b/Kyoo.Common/Kyoo.Common.csproj
@@ -16,13 +16,11 @@
truesnupkgdefault
-
- ENABLE_INTERNAL_LINKS
-
+
diff --git a/Kyoo.Common/Models/Attributes/LinkAttribute.cs b/Kyoo.Common/Models/Attributes/LinkAttribute.cs
deleted file mode 100644
index d98ad90a..00000000
--- a/Kyoo.Common/Models/Attributes/LinkAttribute.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-using System;
-using JetBrains.Annotations;
-using Kyoo.Models.Attributes;
-
-namespace Kyoo.Common.Models.Attributes
-{
- ///
- /// An attribute to mark Link properties on resource.
- ///
- [AttributeUsage(AttributeTargets.Property)]
- [MeansImplicitUse]
- public class LinkAttribute : SerializeIgnoreAttribute { }
-}
\ No newline at end of file
diff --git a/Kyoo.Common/Models/LibraryItem.cs b/Kyoo.Common/Models/LibraryItem.cs
index 6bc61c2e..18680b9e 100644
--- a/Kyoo.Common/Models/LibraryItem.cs
+++ b/Kyoo.Common/Models/LibraryItem.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using System.Linq.Expressions;
using Kyoo.Models.Attributes;
@@ -18,7 +19,7 @@ namespace Kyoo.Models
/// A type union between and .
/// This is used to list content put inside a library.
///
- public class LibraryItem : IResource
+ public class LibraryItem : IResource, IThumbnails
{
///
public int ID { get; set; }
@@ -52,13 +53,17 @@ namespace Kyoo.Models
/// It can also be null if this is unknown.
///
public DateTime? EndAir { get; set; }
-
+
+ ///
+ public Dictionary Images { get; set; }
+
///
/// The path of this item's poster.
/// By default, the http path for this poster is returned from the public API.
/// This can be disabled using the internal query flag.
///
- [SerializeAs("{HOST}/api/{Type:l}/{Slug}/poster")] public string Poster { get; set; }
+ [SerializeAs("{HOST}/api/{Type:l}/{Slug}/poster")]
+ public string Poster => Images?.GetValueOrDefault(Models.Images.Poster);
///
/// The type of this item (ether a collection, a show or a movie).
@@ -84,7 +89,7 @@ namespace Kyoo.Models
Status = show.Status;
StartAir = show.StartAir;
EndAir = show.EndAir;
- Poster = show.Poster;
+ Images = show.Images;
Type = show.IsMovie ? ItemType.Movie : ItemType.Show;
}
@@ -101,7 +106,7 @@ namespace Kyoo.Models
Status = Models.Status.Unknown;
StartAir = null;
EndAir = null;
- Poster = collection.Poster;
+ Images = collection.Images;
Type = ItemType.Collection;
}
@@ -117,7 +122,7 @@ namespace Kyoo.Models
Status = x.Status,
StartAir = x.StartAir,
EndAir = x.EndAir,
- Poster= x.Poster,
+ Images = x.Images,
Type = x.IsMovie ? ItemType.Movie : ItemType.Show
};
@@ -133,7 +138,7 @@ namespace Kyoo.Models
Status = Models.Status.Unknown,
StartAir = null,
EndAir = null,
- Poster = x.Poster,
+ Images = x.Images,
Type = ItemType.Collection
};
}
diff --git a/Kyoo.Common/Models/Link.cs b/Kyoo.Common/Models/Link.cs
deleted file mode 100644
index 09c519da..00000000
--- a/Kyoo.Common/Models/Link.cs
+++ /dev/null
@@ -1,163 +0,0 @@
-using System;
-using System.Linq.Expressions;
-using Kyoo.Models.Attributes;
-
-namespace Kyoo.Models
-{
- ///
- /// A class representing a link between two resources.
- ///
- ///
- /// Links should only be used on the data layer and not on other application code.
- ///
- public class Link
- {
- ///
- /// The ID of the first item of the link.
- /// The first item of the link should be the one to own the link.
- ///
- public int FirstID { get; set; }
-
- ///
- /// The ID of the second item of this link
- /// The second item of the link should be the owned resource.
- ///
- public int SecondID { get; set; }
-
- ///
- /// Create a new typeless .
- ///
- public Link() {}
-
- ///
- /// Create a new typeless with two IDs.
- ///
- /// The ID of the first resource
- /// The ID of the second resource
- public Link(int firstID, int secondID)
- {
- FirstID = firstID;
- SecondID = secondID;
- }
-
- ///
- /// Create a new typeless between two resources.
- ///
- /// The first resource
- /// The second resource
- public Link(IResource first, IResource second)
- {
- FirstID = first.ID;
- SecondID = second.ID;
- }
-
- ///
- /// Create a new typed link between two resources.
- /// This method can be used instead of the constructor to make use of generic parameters deduction.
- ///
- /// The first resource
- /// The second resource
- /// The type of the first resource
- /// The type of the second resource
- /// A newly created typed link with both resources
- public static Link Create(T first, T2 second)
- where T : class, IResource
- where T2 : class, IResource
- {
- return new(first, second);
- }
-
- ///
- /// Create a new typed link between two resources without storing references to resources.
- /// This is the same as but this method does not set
- /// and fields. Only IDs are stored and not references.
- ///
- /// The first resource
- /// The second resource
- /// The type of the first resource
- /// The type of the second resource
- /// A newly created typed link with both resources
- public static Link UCreate(T first, T2 second)
- where T : class, IResource
- where T2 : class, IResource
- {
- return new(first, second, true);
- }
-
- ///
- /// The expression to retrieve the unique ID of a Link. This is an aggregate of the two resources IDs.
- ///
- public static Expression> PrimaryKey
- {
- get
- {
- return x => new {First = x.FirstID, Second = x.SecondID};
- }
- }
- }
-
- ///
- /// A strongly typed link between two resources.
- ///
- /// The type of the first resource
- /// The type of the second resource
- public class Link : Link
- where T1 : class, IResource
- where T2 : class, IResource
- {
- ///
- /// A reference of the first resource.
- ///
- [SerializeIgnore] public T1 First { get; set; }
-
- ///
- /// A reference to the second resource.
- ///
- [SerializeIgnore] public T2 Second { get; set; }
-
-
- ///
- /// Create a new, empty, typed .
- ///
- public Link() {}
-
-
- ///
- /// Create a new typed link with two resources.
- ///
- /// The first resource
- /// The second resource
- ///
- /// True if no reference to resources should be kept, false otherwise.
- /// The default is false (references are kept).
- ///
- public Link(T1 first, T2 second, bool privateItems = false)
- : base(first, second)
- {
- if (privateItems)
- return;
- First = first;
- Second = second;
- }
-
- ///
- /// Create a new typed link with IDs only.
- ///
- /// The ID of the first resource
- /// The ID of the second resource
- public Link(int firstID, int secondID)
- : base(firstID, secondID)
- { }
-
- ///
- /// The expression to retrieve the unique ID of a typed Link. This is an aggregate of the two resources IDs.
- ///
- public new static Expression, object>> PrimaryKey
- {
- get
- {
- return x => new {First = x.FirstID, Second = x.SecondID};
- }
- }
- }
-}
\ No newline at end of file
diff --git a/Kyoo.Common/Models/MetadataID.cs b/Kyoo.Common/Models/MetadataID.cs
index de6ac817..cda4ce11 100644
--- a/Kyoo.Common/Models/MetadataID.cs
+++ b/Kyoo.Common/Models/MetadataID.cs
@@ -1,40 +1,45 @@
using System;
using System.Linq.Expressions;
+using Kyoo.Models.Attributes;
namespace Kyoo.Models
{
///
/// ID and link of an item on an external provider.
///
- ///
- public class MetadataID : Link
- where T : class, IResource
+ public class MetadataID
{
+ ///
+ /// The ID of the resource which possess the metadata.
+ ///
+ [SerializeIgnore] public int ResourceID { get; set; }
+
+ ///
+ /// The ID of the provider.
+ ///
+ [SerializeIgnore] public int ProviderID { get; set; }
+
+ ///
+ /// The provider that can do something with this ID.
+ ///
+ public Provider Provider { get; set; }
+
///
/// The ID of the resource on the external provider.
///
public string DataID { get; set; }
-
+
///
/// The URL of the resource on the external provider.
///
public string Link { get; set; }
- ///
- /// A shortcut to access the provider of this metadata.
- /// Unlike the property, this is serializable.
- ///
- public Provider Provider => Second;
-
///
/// The expression to retrieve the unique ID of a MetadataID. This is an aggregate of the two resources IDs.
///
- public new static Expression, object>> PrimaryKey
+ public static Expression> PrimaryKey
{
- get
- {
- return x => new {First = x.FirstID, Second = x.SecondID};
- }
+ get { return x => new { First = x.ResourceID, Second = x.ProviderID }; }
}
}
}
\ No newline at end of file
diff --git a/Kyoo.Common/Models/PeopleRole.cs b/Kyoo.Common/Models/PeopleRole.cs
index 062bb3e8..daf9c7cd 100644
--- a/Kyoo.Common/Models/PeopleRole.cs
+++ b/Kyoo.Common/Models/PeopleRole.cs
@@ -17,8 +17,8 @@ namespace Kyoo.Models
public string Slug => ForPeople ? Show.Slug : People.Slug;
///
- /// Should this role be used as a Show substitute (the value is false) or
- /// as a People substitute (the value is true).
+ /// Should this role be used as a Show substitute (the value is true) or
+ /// as a People substitute (the value is false).
///
public bool ForPeople { get; set; }
diff --git a/Kyoo.Common/Models/Resources/Collection.cs b/Kyoo.Common/Models/Resources/Collection.cs
index 8162ff16..20cc481b 100644
--- a/Kyoo.Common/Models/Resources/Collection.cs
+++ b/Kyoo.Common/Models/Resources/Collection.cs
@@ -1,5 +1,5 @@
-using System.Collections.Generic;
-using Kyoo.Common.Models.Attributes;
+using System;
+using System.Collections.Generic;
using Kyoo.Models.Attributes;
namespace Kyoo.Models
@@ -8,7 +8,7 @@ namespace Kyoo.Models
/// A class representing collections of .
/// A collection can also be stored in a .
///
- public class Collection : IResource
+ public class Collection : IResource, IMetadata, IThumbnails
{
///
public int ID { get; set; }
@@ -20,14 +20,19 @@ namespace Kyoo.Models
/// The name of this collection.
///
public string Name { get; set; }
+
+ ///
+ public Dictionary Images { get; set; }
///
/// The path of this poster.
/// By default, the http path for this poster is returned from the public API.
/// This can be disabled using the internal query flag.
///
- [SerializeAs("{HOST}/api/collection/{Slug}/poster")] public string Poster { get; set; }
-
+ [SerializeAs("{HOST}/api/collection/{Slug}/poster")]
+ [Obsolete("Use Images instead of this, this is only kept for the API response.")]
+ public string Poster => Images?.GetValueOrDefault(Models.Images.Poster);
+
///
/// The description of this collection.
///
@@ -42,18 +47,8 @@ namespace Kyoo.Models
/// The list of libraries that contains this collection.
///
[LoadableRelation] public ICollection Libraries { get; set; }
-
-#if ENABLE_INTERNAL_LINKS
- ///
- /// The internal link between this collection and shows in the list.
- ///
- [Link] public ICollection> ShowLinks { get; set; }
-
- ///
- /// The internal link between this collection and libraries in the list.
- ///
- [Link] public ICollection> LibraryLinks { get; set; }
-#endif
+ ///
+ [EditableRelation] [LoadableRelation] public ICollection ExternalIDs { get; set; }
}
}
diff --git a/Kyoo.Common/Models/Resources/Episode.cs b/Kyoo.Common/Models/Resources/Episode.cs
index 7f76a8a4..dd1f62e1 100644
--- a/Kyoo.Common/Models/Resources/Episode.cs
+++ b/Kyoo.Common/Models/Resources/Episode.cs
@@ -10,7 +10,7 @@ namespace Kyoo.Models
///
/// A class to represent a single show's episode.
///
- public class Episode : IResource
+ public class Episode : IResource, IMetadata, IThumbnails
{
///
public int ID { get; set; }
@@ -74,9 +74,13 @@ namespace Kyoo.Models
///
[SerializeIgnore] public int? SeasonID { get; set; }
///
- /// The season that contains this episode. This must be explicitly loaded via a call to .
- /// This can be null if the season is unknown and the episode is only identified by it's .
+ /// The season that contains this episode.
+ /// This must be explicitly loaded via a call to .
///
+ ///
+ /// This can be null if the season is unknown and the episode is only identified
+ /// by it's .
+ ///
[LoadableRelation(nameof(SeasonID))] public Season Season { get; set; }
///
@@ -85,7 +89,7 @@ namespace Kyoo.Models
public int? SeasonNumber { get; set; }
///
- /// The number of this episode is it's season.
+ /// The number of this episode in it's season.
///
public int? EpisodeNumber { get; set; }
@@ -98,13 +102,18 @@ namespace Kyoo.Models
/// The path of the video file for this episode. Any format supported by a is allowed.
///
[SerializeIgnore] public string Path { get; set; }
+
+ ///
+ public Dictionary Images { get; set; }
///
/// The path of this episode's thumbnail.
/// By default, the http path for the thumbnail is returned from the public API.
/// This can be disabled using the internal query flag.
///
- [SerializeAs("{HOST}/api/episodes/{Slug}/thumb")] public string Thumb { get; set; }
+ [SerializeAs("{HOST}/api/episodes/{Slug}/thumbnail")]
+ [Obsolete("Use Images instead of this, this is only kept for the API response.")]
+ public string Thumb => Images?.GetValueOrDefault(Models.Images.Thumbnail);
///
/// The title of this episode.
@@ -121,10 +130,8 @@ namespace Kyoo.Models
///
public DateTime? ReleaseDate { get; set; }
- ///
- /// The link to metadata providers that this episode has. See for more information.
- ///
- [EditableRelation] [LoadableRelation] public ICollection> ExternalIDs { get; set; }
+ ///
+ [EditableRelation] [LoadableRelation] public ICollection ExternalIDs { get; set; }
///
/// The list of tracks this episode has. This lists video, audio and subtitles available.
diff --git a/Kyoo.Common/Models/Resources/Genre.cs b/Kyoo.Common/Models/Resources/Genre.cs
index c7aaa76f..e5fcbed8 100644
--- a/Kyoo.Common/Models/Resources/Genre.cs
+++ b/Kyoo.Common/Models/Resources/Genre.cs
@@ -1,5 +1,4 @@
using System.Collections.Generic;
-using Kyoo.Common.Models.Attributes;
using Kyoo.Models.Attributes;
namespace Kyoo.Models
@@ -24,14 +23,7 @@ namespace Kyoo.Models
/// The list of shows that have this genre.
///
[LoadableRelation] public ICollection Shows { get; set; }
-
-#if ENABLE_INTERNAL_LINKS
- ///
- /// The internal link between this genre and shows in the list.
- ///
- [Link] public ICollection> ShowLinks { get; set; }
-#endif
-
+
///
/// Create a new, empty .
///
diff --git a/Kyoo.Common/Models/Resources/Interfaces/IMetadata.cs b/Kyoo.Common/Models/Resources/Interfaces/IMetadata.cs
new file mode 100644
index 00000000..ef1e6bbc
--- /dev/null
+++ b/Kyoo.Common/Models/Resources/Interfaces/IMetadata.cs
@@ -0,0 +1,79 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using JetBrains.Annotations;
+using Kyoo.Models.Attributes;
+
+namespace Kyoo.Models
+{
+ ///
+ /// An interface applied to resources containing external metadata.
+ ///
+ public interface IMetadata
+ {
+ ///
+ /// The link to metadata providers that this show has. See for more information.
+ ///
+ [EditableRelation] [LoadableRelation]
+ public ICollection ExternalIDs { get; set; }
+ }
+
+ ///
+ /// A static class containing extensions method for every class.
+ /// This allow one to use metadata more easily.
+ ///
+ public static class MetadataExtension
+ {
+ ///
+ /// Retrieve the internal provider's ID of an item using it's provider slug.
+ ///
+ ///
+ /// This method will never return anything if the are not loaded.
+ ///
+ /// An instance of to retrieve the ID from.
+ /// The slug of the provider
+ /// The field of the asked provider.
+ [CanBeNull]
+ public static string GetID(this IMetadata self, string provider)
+ {
+ return self.ExternalIDs?.FirstOrDefault(x => x.Provider.Slug == provider)?.DataID;
+ }
+
+ ///
+ /// Retrieve the internal provider's ID of an item using it's provider slug.
+ /// If the ID could be found, it is converted to the type and true is returned.
+ ///
+ ///
+ /// This method will never succeed if the are not loaded.
+ ///
+ /// An instance of to retrieve the ID from.
+ /// The slug of the provider
+ ///
+ /// The field of the asked provider parsed
+ /// and converted to the type.
+ /// It is only relevant if this method returns true.
+ ///
+ /// The type to convert the to.
+ /// true if this method succeeded, false otherwise.
+ public static bool TryGetID(this IMetadata self, string provider, out T id)
+ {
+ string dataID = self.ExternalIDs?.FirstOrDefault(x => x.Provider.Slug == provider)?.DataID;
+ if (dataID == null)
+ {
+ id = default;
+ return false;
+ }
+
+ try
+ {
+ id = (T)Convert.ChangeType(dataID, typeof(T));
+ }
+ catch
+ {
+ id = default;
+ return false;
+ }
+ return true;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Kyoo.Common/Models/Resources/IResource.cs b/Kyoo.Common/Models/Resources/Interfaces/IResource.cs
similarity index 100%
rename from Kyoo.Common/Models/Resources/IResource.cs
rename to Kyoo.Common/Models/Resources/Interfaces/IResource.cs
diff --git a/Kyoo.Common/Models/Resources/Interfaces/IThumbnails.cs b/Kyoo.Common/Models/Resources/Interfaces/IThumbnails.cs
new file mode 100644
index 00000000..ba4999de
--- /dev/null
+++ b/Kyoo.Common/Models/Resources/Interfaces/IThumbnails.cs
@@ -0,0 +1,49 @@
+using System.Collections.Generic;
+using Kyoo.Controllers;
+
+namespace Kyoo.Models
+{
+ ///
+ /// An interface representing items that contains images (like posters, thumbnails, logo, banners...)
+ ///
+ public interface IThumbnails
+ {
+ ///
+ /// The list of images mapped to a certain index.
+ /// The string value should be a path supported by the .
+ ///
+ ///
+ /// An arbitrary index should not be used, instead use indexes from
+ ///
+ public Dictionary Images { get; set; }
+
+ // TODO remove Posters properties add them via the json serializer for every IThumbnails
+ }
+
+ ///
+ /// A class containing constant values for images. To be used as index of a .
+ ///
+ public static class Images
+ {
+ ///
+ /// A poster is a 9/16 format image with the cover of the resource.
+ ///
+ public const int Poster = 0;
+
+ ///
+ /// A thumbnail is a 16/9 format image, it could ether be used as a background or as a preview but it usually
+ /// is not an official image.
+ ///
+ public const int Thumbnail = 1;
+
+ ///
+ /// A logo is a small image representing the resource.
+ ///
+ public const int Logo = 2;
+
+ ///
+ /// A video of a few minutes that tease the content.
+ ///
+ public const int Trailer = 3;
+ }
+}
\ No newline at end of file
diff --git a/Kyoo.Common/Models/Resources/Library.cs b/Kyoo.Common/Models/Resources/Library.cs
index a72d6a37..6580f988 100644
--- a/Kyoo.Common/Models/Resources/Library.cs
+++ b/Kyoo.Common/Models/Resources/Library.cs
@@ -1,5 +1,4 @@
using System.Collections.Generic;
-using Kyoo.Common.Models.Attributes;
using Kyoo.Models.Attributes;
namespace Kyoo.Models
@@ -39,22 +38,5 @@ namespace Kyoo.Models
/// The list of collections in this library.
///
[LoadableRelation] public ICollection Collections { get; set; }
-
-#if ENABLE_INTERNAL_LINKS
- ///
- /// The internal link between this library and provider in the list.
- ///
- [Link] public ICollection> ProviderLinks { get; set; }
-
- ///
- /// The internal link between this library and shows in the list.
- ///
- [Link] public ICollection> ShowLinks { get; set; }
-
- ///
- /// The internal link between this library and collection in the list.
- ///
- [Link] public ICollection> CollectionLinks { get; set; }
-#endif
}
}
diff --git a/Kyoo.Common/Models/Resources/People.cs b/Kyoo.Common/Models/Resources/People.cs
index 7ae04613..7bd59620 100644
--- a/Kyoo.Common/Models/Resources/People.cs
+++ b/Kyoo.Common/Models/Resources/People.cs
@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
using Kyoo.Models.Attributes;
namespace Kyoo.Models
@@ -6,7 +7,7 @@ namespace Kyoo.Models
///
/// An actor, voice actor, writer, animator, somebody who worked on a .
///
- public class People : IResource
+ public class People : IResource, IMetadata, IThumbnails
{
///
public int ID { get; set; }
@@ -19,17 +20,20 @@ namespace Kyoo.Models
///
public string Name { get; set; }
+ ///
+ public Dictionary Images { get; set; }
+
///
/// The path of this poster.
/// By default, the http path for this poster is returned from the public API.
/// This can be disabled using the internal query flag.
///
- [SerializeAs("{HOST}/api/people/{Slug}/poster")] public string Poster { get; set; }
+ [SerializeAs("{HOST}/api/people/{Slug}/poster")]
+ [Obsolete("Use Images instead of this, this is only kept for the API response.")]
+ public string Poster => Images?.GetValueOrDefault(Models.Images.Poster);
- ///
- /// The link to metadata providers that this person has. See for more information.
- ///
- [EditableRelation] [LoadableRelation] public ICollection> ExternalIDs { get; set; }
+ ///
+ [EditableRelation] [LoadableRelation] public ICollection ExternalIDs { get; set; }
///
/// The list of roles this person has played in. See for more information.
diff --git a/Kyoo.Common/Models/Resources/Provider.cs b/Kyoo.Common/Models/Resources/Provider.cs
index e13a9be4..31b87f3f 100644
--- a/Kyoo.Common/Models/Resources/Provider.cs
+++ b/Kyoo.Common/Models/Resources/Provider.cs
@@ -1,5 +1,5 @@
+using System;
using System.Collections.Generic;
-using Kyoo.Common.Models.Attributes;
using Kyoo.Controllers;
using Kyoo.Models.Attributes;
@@ -9,7 +9,7 @@ namespace Kyoo.Models
/// This class contains metadata about .
/// You can have providers even if you don't have the corresponding .
///
- public class Provider : IResource
+ public class Provider : IResource, IThumbnails
{
///
public int ID { get; set; }
@@ -22,30 +22,23 @@ namespace Kyoo.Models
///
public string Name { get; set; }
+ ///
+ public Dictionary Images { get; set; }
+
///
/// The path of this provider's logo.
/// By default, the http path for this logo is returned from the public API.
/// This can be disabled using the internal query flag.
///
- [SerializeAs("{HOST}/api/providers/{Slug}/logo")] public string Logo { get; set; }
-
- ///
- /// The extension of the logo. This is used for http responses.
- ///
- [SerializeIgnore] public string LogoExtension { get; set; }
-
+ [SerializeAs("{HOST}/api/providers/{Slug}/logo")]
+ [Obsolete("Use Images instead of this, this is only kept for the API response.")]
+ public string Logo => Images?.GetValueOrDefault(Models.Images.Logo);
+
///
/// The list of libraries that uses this provider.
///
[LoadableRelation] public ICollection Libraries { get; set; }
-
-#if ENABLE_INTERNAL_LINKS
- ///
- /// The internal link between this provider and libraries in the list.
- ///
- [Link] public ICollection> LibraryLinks { get; set; }
-#endif
-
+
///
/// Create a new, default,
///
@@ -61,7 +54,10 @@ namespace Kyoo.Models
{
Slug = Utility.ToSlug(name);
Name = name;
- Logo = logo;
+ Images = new Dictionary
+ {
+ [Models.Images.Logo] = logo
+ };
}
}
}
\ No newline at end of file
diff --git a/Kyoo.Common/Models/Resources/Season.cs b/Kyoo.Common/Models/Resources/Season.cs
index 9b292020..2c5d59eb 100644
--- a/Kyoo.Common/Models/Resources/Season.cs
+++ b/Kyoo.Common/Models/Resources/Season.cs
@@ -10,7 +10,7 @@ namespace Kyoo.Models
///
/// A season of a .
///
- public class Season : IResource
+ public class Season : IResource, IMetadata, IThumbnails
{
///
public int ID { get; set; }
@@ -45,7 +45,8 @@ namespace Kyoo.Models
///
[SerializeIgnore] public int ShowID { get; set; }
///
- /// The show that contains this season. This must be explicitly loaded via a call to .
+ /// The show that contains this season.
+ /// This must be explicitly loaded via a call to .
///
[LoadableRelation(nameof(ShowID))] public Show Show { get; set; }
@@ -74,17 +75,20 @@ namespace Kyoo.Models
///
public DateTime? EndDate { get; set; }
+ ///
+ public Dictionary Images { get; set; }
+
///
/// The path of this poster.
/// By default, the http path for this poster is returned from the public API.
/// This can be disabled using the internal query flag.
///
- [SerializeAs("{HOST}/api/seasons/{Slug}/thumb")] public string Poster { get; set; }
+ [SerializeAs("{HOST}/api/seasons/{Slug}/thumb")]
+ [Obsolete("Use Images instead of this, this is only kept for the API response.")]
+ public string Poster => Images?.GetValueOrDefault(Models.Images.Poster);
- ///
- /// The link to metadata providers that this episode has. See for more information.
- ///
- [EditableRelation] [LoadableRelation] public ICollection> ExternalIDs { get; set; }
+ ///
+ [EditableRelation] [LoadableRelation] public ICollection ExternalIDs { get; set; }
///
/// The list of episodes that this season contains.
diff --git a/Kyoo.Common/Models/Resources/Show.cs b/Kyoo.Common/Models/Resources/Show.cs
index 57c9fcef..03c86e5e 100644
--- a/Kyoo.Common/Models/Resources/Show.cs
+++ b/Kyoo.Common/Models/Resources/Show.cs
@@ -1,8 +1,5 @@
using System;
using System.Collections.Generic;
-using System.Linq;
-using JetBrains.Annotations;
-using Kyoo.Common.Models.Attributes;
using Kyoo.Controllers;
using Kyoo.Models.Attributes;
@@ -11,7 +8,7 @@ namespace Kyoo.Models
///
/// A series or a movie.
///
- public class Show : IResource, IOnMerge
+ public class Show : IResource, IMetadata, IOnMerge, IThumbnails
{
///
public int ID { get; set; }
@@ -44,12 +41,13 @@ namespace Kyoo.Models
/// Is this show airing, not aired yet or finished?
///
public Status Status { get; set; }
-
+
///
/// An URL to a trailer. This could be any path supported by the .
///
/// TODO for now, this is set to a youtube url. It should be cached and converted to a local file.
- public string TrailerUrl { get; set; }
+ [Obsolete("Use Images instead of this, this is only kept for the API response.")]
+ public string TrailerUrl => Images?.GetValueOrDefault(Models.Images.Trailer);
///
/// The date this show started airing. It can be null if this is unknown.
@@ -63,43 +61,51 @@ namespace Kyoo.Models
///
public DateTime? EndAir { get; set; }
+ ///
+ public Dictionary Images { get; set; }
+
///
/// The path of this show's poster.
/// By default, the http path for this poster is returned from the public API.
/// This can be disabled using the internal query flag.
///
- [SerializeAs("{HOST}/api/shows/{Slug}/poster")] public string Poster { get; set; }
-
+ [SerializeAs("{HOST}/api/shows/{Slug}/poster")]
+ [Obsolete("Use Images instead of this, this is only kept for the API response.")]
+ public string Poster => Images?.GetValueOrDefault(Models.Images.Poster);
+
///
/// The path of this show's logo.
/// By default, the http path for this logo is returned from the public API.
/// This can be disabled using the internal query flag.
///
- [SerializeAs("{HOST}/api/shows/{Slug}/logo")] public string Logo { get; set; }
-
+ [SerializeAs("{HOST}/api/shows/{Slug}/logo")]
+ [Obsolete("Use Images instead of this, this is only kept for the API response.")]
+ public string Logo => Images?.GetValueOrDefault(Models.Images.Logo);
+
///
/// The path of this show's backdrop.
/// By default, the http path for this backdrop is returned from the public API.
/// This can be disabled using the internal query flag.
///
- [SerializeAs("{HOST}/api/shows/{Slug}/backdrop")] public string Backdrop { get; set; }
+ [SerializeAs("{HOST}/api/shows/{Slug}/backdrop")]
+ [Obsolete("Use Images instead of this, this is only kept for the API response.")]
+ public string Backdrop => Images?.GetValueOrDefault(Models.Images.Thumbnail);
///
/// True if this show represent a movie, false otherwise.
///
public bool IsMovie { get; set; }
- ///
- /// The link to metadata providers that this show has. See for more information.
- ///
- [EditableRelation] [LoadableRelation] public ICollection> ExternalIDs { get; set; }
-
+ ///
+ [EditableRelation] [LoadableRelation] public ICollection ExternalIDs { get; set; }
+
///
/// The ID of the Studio that made this show.
///
[SerializeIgnore] public int? StudioID { get; set; }
///
- /// The Studio that made this show. This must be explicitly loaded via a call to .
+ /// The Studio that made this show.
+ /// This must be explicitly loaded via a call to .
///
[LoadableRelation(nameof(StudioID))] [EditableRelation] public Studio Studio { get; set; }
@@ -135,41 +141,9 @@ namespace Kyoo.Models
///
[LoadableRelation] public ICollection Collections { get; set; }
-#if ENABLE_INTERNAL_LINKS
- ///
- /// The internal link between this show and libraries in the list.
- ///
- [Link] public ICollection> LibraryLinks { get; set; }
-
- ///
- /// The internal link between this show and collections in the list.
- ///
- [Link] public ICollection> CollectionLinks { get; set; }
-
- ///
- /// The internal link between this show and genres in the list.
- ///
- [Link] public ICollection> GenreLinks { get; set; }
-#endif
-
- ///
- /// Retrieve the internal provider's ID of a show using it's provider slug.
- ///
- /// This method will never return anything if the are not loaded.
- /// The slug of the provider
- /// The field of the asked provider.
- [CanBeNull]
- public string GetID(string provider)
- {
- return ExternalIDs?.FirstOrDefault(x => x.Second.Slug == provider)?.DataID;
- }
-
///
public void OnMerge(object merged)
{
- if (ExternalIDs != null)
- foreach (MetadataID id in ExternalIDs)
- id.First = this;
if (People != null)
foreach (PeopleRole link in People)
link.Show = this;
diff --git a/Kyoo.Common/Models/Resources/Studio.cs b/Kyoo.Common/Models/Resources/Studio.cs
index ebc3c4c1..03ec04df 100644
--- a/Kyoo.Common/Models/Resources/Studio.cs
+++ b/Kyoo.Common/Models/Resources/Studio.cs
@@ -6,7 +6,7 @@ namespace Kyoo.Models
///
/// A studio that make shows.
///
- public class Studio : IResource
+ public class Studio : IResource, IMetadata
{
///
public int ID { get; set; }
@@ -24,6 +24,9 @@ namespace Kyoo.Models
///
[LoadableRelation] public ICollection Shows { get; set; }
+ ///
+ [EditableRelation] [LoadableRelation] public ICollection ExternalIDs { get; set; }
+
///
/// Create a new, empty, .
///
diff --git a/Kyoo.Common/Models/Resources/User.cs b/Kyoo.Common/Models/Resources/User.cs
index 05f56534..3400df62 100644
--- a/Kyoo.Common/Models/Resources/User.cs
+++ b/Kyoo.Common/Models/Resources/User.cs
@@ -1,12 +1,11 @@
using System.Collections.Generic;
-using Kyoo.Common.Models.Attributes;
namespace Kyoo.Models
{
///
/// A single user of the app.
///
- public class User : IResource
+ public class User : IResource, IThumbnails
{
///
public int ID { get; set; }
@@ -38,7 +37,10 @@ namespace Kyoo.Models
/// Arbitrary extra data that can be used by specific authentication implementations.
///
public Dictionary ExtraData { get; set; }
-
+
+ ///
+ public Dictionary Images { get; set; }
+
///
/// The list of shows the user has finished.
///
@@ -48,20 +50,28 @@ namespace Kyoo.Models
/// The list of episodes the user is watching (stopped in progress or the next episode of the show)
///
public ICollection CurrentlyWatching { get; set; }
-
-#if ENABLE_INTERNAL_LINKS
- ///
- /// Links between Users and Shows.
- ///
- [Link] public ICollection> ShowLinks { get; set; }
-#endif
}
///
/// Metadata of episode currently watching by an user
///
- public class WatchedEpisode : Link
+ public class WatchedEpisode
{
+ ///
+ /// The ID of the user that started watching this episode.
+ ///
+ public int UserID { get; set; }
+
+ ///
+ /// The ID of the episode started.
+ ///
+ public int EpisodeID { get; set; }
+
+ ///
+ /// The started.
+ ///
+ public Episode Episode { get; set; }
+
///
/// Where the player has stopped watching the episode (between 0 and 100).
///
diff --git a/Kyoo.Common/Utility/Merger.cs b/Kyoo.Common/Utility/Merger.cs
index cd860ea3..3c2d6247 100644
--- a/Kyoo.Common/Utility/Merger.cs
+++ b/Kyoo.Common/Utility/Merger.cs
@@ -22,12 +22,13 @@ namespace Kyoo
/// The second enumerable to merge, if items from this list are equals to one from the first, they are not kept
/// Equality function to compare items. If this is null, duplicated elements are kept
/// The two list merged as an array
- public static T[] MergeLists(IEnumerable first,
- IEnumerable second,
- Func isEqual = null)
+ [ContractAnnotation("first:notnull => notnull; second:notnull => notnull", true)]
+ public static T[] MergeLists([CanBeNull] IEnumerable first,
+ [CanBeNull] IEnumerable second,
+ [CanBeNull] Func isEqual = null)
{
if (first == null)
- return second.ToArray();
+ return second?.ToArray();
if (second == null)
return first.ToArray();
if (isEqual == null)
@@ -36,6 +37,98 @@ namespace Kyoo
return list.Concat(second.Where(x => !list.Any(y => isEqual(x, y)))).ToArray();
}
+ ///
+ /// Merge two dictionary, if the same key is found on both dictionary, the values of the first one is kept.
+ ///
+ /// The first dictionary to merge
+ /// The second dictionary to merge
+ /// The type of the keys in dictionaries
+ /// The type of values in the dictionaries
+ /// The first dictionary with the missing elements of .
+ ///
+ [ContractAnnotation("first:notnull => notnull; second:notnull => notnull", true)]
+ public static IDictionary MergeDictionaries([CanBeNull] IDictionary first,
+ [CanBeNull] IDictionary second)
+ {
+ return MergeDictionaries(first, second, out bool _);
+ }
+
+ ///
+ /// Merge two dictionary, if the same key is found on both dictionary, the values of the first one is kept.
+ ///
+ /// The first dictionary to merge
+ /// The second dictionary to merge
+ ///
+ /// true if a new items has been added to the dictionary, false otherwise.
+ ///
+ /// The type of the keys in dictionaries
+ /// The type of values in the dictionaries
+ /// The first dictionary with the missing elements of .
+ [ContractAnnotation("first:notnull => notnull; second:notnull => notnull", true)]
+ public static IDictionary MergeDictionaries([CanBeNull] IDictionary first,
+ [CanBeNull] IDictionary second,
+ out bool hasChanged)
+ {
+ if (first == null)
+ {
+ hasChanged = true;
+ return second;
+ }
+
+ hasChanged = false;
+ if (second == null)
+ return first;
+ foreach ((T key, T2 value) in second)
+ hasChanged |= first.TryAdd(key, value);
+ return first;
+ }
+
+ ///
+ /// Merge two dictionary, if the same key is found on both dictionary, the values of the second one is kept.
+ ///
+ ///
+ /// The only difference in this function compared to
+ ///
+ /// is the way is calculated and the order of the arguments.
+ ///
+ /// MergeDictionaries(first, second);
+ ///
+ /// will do the same thing as
+ ///
+ /// CompleteDictionaries(second, first, out bool _);
+ ///
+ ///
+ /// The first dictionary to merge
+ /// The second dictionary to merge
+ ///
+ /// true if a new items has been added to the dictionary, false otherwise.
+ ///
+ /// The type of the keys in dictionaries
+ /// The type of values in the dictionaries
+ ///
+ /// A dictionary with the missing elements of
+ /// set to those of .
+ ///
+ [ContractAnnotation("first:notnull => notnull; second:notnull => notnull", true)]
+ public static IDictionary CompleteDictionaries([CanBeNull] IDictionary first,
+ [CanBeNull] IDictionary second,
+ out bool hasChanged)
+ {
+ if (first == null)
+ {
+ hasChanged = true;
+ return second;
+ }
+
+ hasChanged = false;
+ if (second == null)
+ return first;
+ hasChanged = second.Any(x => !x.Value.Equals(first[x.Key]));
+ foreach ((T key, T2 value) in first)
+ second.TryAdd(key, value);
+ return second;
+ }
+
///
/// Set every fields of first to those of second. Ignore fields marked with the attribute
/// At the end, the OnMerge method of first will be called if first is a
@@ -63,16 +156,34 @@ namespace Kyoo
}
///
- /// Set every default values of first to the value of second. ex: {id: 0, slug: "test"}, {id: 4, slug: "foo"} -> {id: 4, slug: "test"}.
+ /// Set every non-default values of seconds to the corresponding property of second.
+ /// Dictionaries are handled like anonymous objects with a property per key/pair value
+ /// (see
+ ///
+ /// for more details).
/// At the end, the OnMerge method of first will be called if first is a
///
- /// The object to complete
- /// Missing fields of first will be completed by fields of this item. If second is null, the function no-op.
- /// Filter fields that will be merged
+ ///
+ /// This does the opposite of .
+ ///
+ ///
+ /// {id: 0, slug: "test"}, {id: 4, slug: "foo"} -> {id: 4, slug: "foo"}
+ ///
+ ///
+ /// The object to complete
+ ///
+ ///
+ /// Missing fields of first will be completed by fields of this item. If second is null, the function no-op.
+ ///
+ ///
+ /// Filter fields that will be merged
+ ///
/// Fields of T will be completed
///
/// If first is null
- public static T Complete([NotNull] T first, [CanBeNull] T second, Func where = null)
+ public static T Complete([NotNull] T first,
+ [CanBeNull] T second,
+ [InstantHandle] Func where = null)
{
if (first == null)
throw new ArgumentNullException(nameof(first));
@@ -93,7 +204,26 @@ namespace Kyoo
object defaultValue = property.GetCustomAttribute()?.Value
?? property.PropertyType.GetClrDefault();
- if (value?.Equals(defaultValue) == false && value != property.GetValue(first))
+ if (value?.Equals(defaultValue) != false || value.Equals(property.GetValue(first)))
+ continue;
+ if (Utility.IsOfGenericType(property.PropertyType, typeof(IDictionary<,>)))
+ {
+ Type[] dictionaryTypes = Utility.GetGenericDefinition(property.PropertyType, typeof(IDictionary<,>))
+ .GenericTypeArguments;
+ object[] parameters = {
+ property.GetValue(first),
+ value,
+ false
+ };
+ object newDictionary = Utility.RunGenericMethod
private void DiscardChanges()
{
- foreach (EntityEntry entry in ChangeTracker.Entries().Where(x => x.State != EntityState.Unchanged
- && x.State != EntityState.Detached))
+ foreach (EntityEntry entry in ChangeTracker.Entries().Where(x => x.State != EntityState.Detached))
{
entry.State = EntityState.Detached;
}
}
-
-
+
///
/// Perform a case insensitive like operation.
///
diff --git a/Kyoo.CommonAPI/LocalRepository.cs b/Kyoo.CommonAPI/LocalRepository.cs
index 0187e0dd..67a75e12 100644
--- a/Kyoo.CommonAPI/LocalRepository.cs
+++ b/Kyoo.CommonAPI/LocalRepository.cs
@@ -234,16 +234,23 @@ namespace Kyoo.Controllers
finally
{
Database.ChangeTracker.LazyLoadingEnabled = lazyLoading;
+ Database.ChangeTracker.Clear();
}
}
///
/// An overridable method to edit relation of a resource.
///
- /// The non edited resource
- /// The new version of . This item will be saved on the databse and replace
- /// A boolean to indicate if all values of resource should be discarded or not.
- ///
+ ///
+ /// The non edited resource
+ ///
+ ///
+ /// The new version of .
+ /// This item will be saved on the database and replace
+ ///
+ ///
+ /// A boolean to indicate if all values of resource should be discarded or not.
+ ///
protected virtual Task EditRelations(T resource, T changed, bool resetOld)
{
return Validate(resource);
@@ -254,7 +261,9 @@ namespace Kyoo.Controllers
/// It is also called on the default implementation of
///
/// The resource that will be saved
- /// You can throw this if the resource is illegal and should not be saved.
+ ///
+ /// You can throw this if the resource is illegal and should not be saved.
+ ///
protected virtual Task Validate(T resource)
{
if (typeof(T).GetProperty(nameof(resource.Slug))!.GetCustomAttribute() != null)
diff --git a/Kyoo.Postgresql/Migrations/20210723224326_Initial.Designer.cs b/Kyoo.Postgresql/Migrations/20210801171613_Initial.Designer.cs
similarity index 70%
rename from Kyoo.Postgresql/Migrations/20210723224326_Initial.Designer.cs
rename to Kyoo.Postgresql/Migrations/20210801171613_Initial.Designer.cs
index 3016a040..20b6f7bd 100644
--- a/Kyoo.Postgresql/Migrations/20210723224326_Initial.Designer.cs
+++ b/Kyoo.Postgresql/Migrations/20210801171613_Initial.Designer.cs
@@ -12,7 +12,7 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace Kyoo.Postgresql.Migrations
{
[DbContext(typeof(PostgresContext))]
- [Migration("20210723224326_Initial")]
+ [Migration("20210801171613_Initial")]
partial class Initial
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
@@ -34,6 +34,10 @@ namespace Kyoo.Postgresql.Migrations
.HasColumnName("id")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
+ b.Property>("Images")
+ .HasColumnType("jsonb")
+ .HasColumnName("images");
+
b.Property("Name")
.HasColumnType("text")
.HasColumnName("name");
@@ -42,10 +46,6 @@ namespace Kyoo.Postgresql.Migrations
.HasColumnType("text")
.HasColumnName("overview");
- b.Property("Poster")
- .HasColumnType("text")
- .HasColumnName("poster");
-
b.Property("Slug")
.IsRequired()
.HasColumnType("text")
@@ -77,6 +77,10 @@ namespace Kyoo.Postgresql.Migrations
.HasColumnType("integer")
.HasColumnName("episode_number");
+ b.Property>("Images")
+ .HasColumnType("jsonb")
+ .HasColumnName("images");
+
b.Property("Overview")
.HasColumnType("text")
.HasColumnName("overview");
@@ -106,10 +110,6 @@ namespace Kyoo.Postgresql.Migrations
.HasColumnType("text")
.HasColumnName("slug");
- b.Property("Thumb")
- .HasColumnType("text")
- .HasColumnName("thumb");
-
b.Property("Title")
.HasColumnType("text")
.HasColumnName("title");
@@ -200,14 +200,14 @@ namespace Kyoo.Postgresql.Migrations
.HasColumnType("timestamp without time zone")
.HasColumnName("end_air");
+ b.Property>("Images")
+ .HasColumnType("jsonb")
+ .HasColumnName("images");
+
b.Property("Overview")
.HasColumnType("text")
.HasColumnName("overview");
- b.Property("Poster")
- .HasColumnType("text")
- .HasColumnName("poster");
-
b.Property("Slug")
.HasColumnType("text")
.HasColumnName("slug");
@@ -234,228 +234,6 @@ namespace Kyoo.Postgresql.Migrations
b.ToView("library_items");
});
- modelBuilder.Entity("Kyoo.Models.Link", b =>
- {
- b.Property("FirstID")
- .HasColumnType("integer")
- .HasColumnName("first_id");
-
- b.Property("SecondID")
- .HasColumnType("integer")
- .HasColumnName("second_id");
-
- b.HasKey("FirstID", "SecondID")
- .HasName("pk_link_collection_show");
-
- b.HasIndex("SecondID")
- .HasDatabaseName("ix_link_collection_show_second_id");
-
- b.ToTable("link_collection_show");
- });
-
- modelBuilder.Entity("Kyoo.Models.Link", b =>
- {
- b.Property("FirstID")
- .HasColumnType("integer")
- .HasColumnName("first_id");
-
- b.Property("SecondID")
- .HasColumnType("integer")
- .HasColumnName("second_id");
-
- b.HasKey("FirstID", "SecondID")
- .HasName("pk_link_library_collection");
-
- b.HasIndex("SecondID")
- .HasDatabaseName("ix_link_library_collection_second_id");
-
- b.ToTable("link_library_collection");
- });
-
- modelBuilder.Entity("Kyoo.Models.Link", b =>
- {
- b.Property("FirstID")
- .HasColumnType("integer")
- .HasColumnName("first_id");
-
- b.Property("SecondID")
- .HasColumnType("integer")
- .HasColumnName("second_id");
-
- b.HasKey("FirstID", "SecondID")
- .HasName("pk_link_library_provider");
-
- b.HasIndex("SecondID")
- .HasDatabaseName("ix_link_library_provider_second_id");
-
- b.ToTable("link_library_provider");
- });
-
- modelBuilder.Entity("Kyoo.Models.Link", b =>
- {
- b.Property("FirstID")
- .HasColumnType("integer")
- .HasColumnName("first_id");
-
- b.Property("SecondID")
- .HasColumnType("integer")
- .HasColumnName("second_id");
-
- b.HasKey("FirstID", "SecondID")
- .HasName("pk_link_library_show");
-
- b.HasIndex("SecondID")
- .HasDatabaseName("ix_link_library_show_second_id");
-
- b.ToTable("link_library_show");
- });
-
- modelBuilder.Entity("Kyoo.Models.Link", b =>
- {
- b.Property("FirstID")
- .HasColumnType("integer")
- .HasColumnName("first_id");
-
- b.Property("SecondID")
- .HasColumnType("integer")
- .HasColumnName("second_id");
-
- b.HasKey("FirstID", "SecondID")
- .HasName("pk_link_show_genre");
-
- b.HasIndex("SecondID")
- .HasDatabaseName("ix_link_show_genre_second_id");
-
- b.ToTable("link_show_genre");
- });
-
- modelBuilder.Entity("Kyoo.Models.Link", b =>
- {
- b.Property("FirstID")
- .HasColumnType("integer")
- .HasColumnName("first_id");
-
- b.Property("SecondID")
- .HasColumnType("integer")
- .HasColumnName("second_id");
-
- b.HasKey("FirstID", "SecondID")
- .HasName("pk_link_user_show");
-
- b.HasIndex("SecondID")
- .HasDatabaseName("ix_link_user_show_second_id");
-
- b.ToTable("link_user_show");
- });
-
- modelBuilder.Entity("Kyoo.Models.MetadataID", b =>
- {
- b.Property("FirstID")
- .HasColumnType("integer")
- .HasColumnName("first_id");
-
- b.Property("SecondID")
- .HasColumnType("integer")
- .HasColumnName("second_id");
-
- b.Property("DataID")
- .HasColumnType("text")
- .HasColumnName("data_id");
-
- b.Property("Link")
- .HasColumnType("text")
- .HasColumnName("link");
-
- b.HasKey("FirstID", "SecondID")
- .HasName("pk_metadata_id_episode");
-
- b.HasIndex("SecondID")
- .HasDatabaseName("ix_metadata_id_episode_second_id");
-
- b.ToTable("metadata_id_episode");
- });
-
- modelBuilder.Entity("Kyoo.Models.MetadataID", b =>
- {
- b.Property("FirstID")
- .HasColumnType("integer")
- .HasColumnName("first_id");
-
- b.Property("SecondID")
- .HasColumnType("integer")
- .HasColumnName("second_id");
-
- b.Property("DataID")
- .HasColumnType("text")
- .HasColumnName("data_id");
-
- b.Property("Link")
- .HasColumnType("text")
- .HasColumnName("link");
-
- b.HasKey("FirstID", "SecondID")
- .HasName("pk_metadata_id_people");
-
- b.HasIndex("SecondID")
- .HasDatabaseName("ix_metadata_id_people_second_id");
-
- b.ToTable("metadata_id_people");
- });
-
- modelBuilder.Entity("Kyoo.Models.MetadataID", b =>
- {
- b.Property("FirstID")
- .HasColumnType("integer")
- .HasColumnName("first_id");
-
- b.Property("SecondID")
- .HasColumnType("integer")
- .HasColumnName("second_id");
-
- b.Property("DataID")
- .HasColumnType("text")
- .HasColumnName("data_id");
-
- b.Property("Link")
- .HasColumnType("text")
- .HasColumnName("link");
-
- b.HasKey("FirstID", "SecondID")
- .HasName("pk_metadata_id_season");
-
- b.HasIndex("SecondID")
- .HasDatabaseName("ix_metadata_id_season_second_id");
-
- b.ToTable("metadata_id_season");
- });
-
- modelBuilder.Entity("Kyoo.Models.MetadataID", b =>
- {
- b.Property("FirstID")
- .HasColumnType("integer")
- .HasColumnName("first_id");
-
- b.Property("SecondID")
- .HasColumnType("integer")
- .HasColumnName("second_id");
-
- b.Property("DataID")
- .HasColumnType("text")
- .HasColumnName("data_id");
-
- b.Property("Link")
- .HasColumnType("text")
- .HasColumnName("link");
-
- b.HasKey("FirstID", "SecondID")
- .HasName("pk_metadata_id_show");
-
- b.HasIndex("SecondID")
- .HasDatabaseName("ix_metadata_id_show_second_id");
-
- b.ToTable("metadata_id_show");
- });
-
modelBuilder.Entity("Kyoo.Models.People", b =>
{
b.Property("ID")
@@ -464,14 +242,14 @@ namespace Kyoo.Postgresql.Migrations
.HasColumnName("id")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
+ b.Property>("Images")
+ .HasColumnType("jsonb")
+ .HasColumnName("images");
+
b.Property("Name")
.HasColumnType("text")
.HasColumnName("name");
- b.Property("Poster")
- .HasColumnType("text")
- .HasColumnName("poster");
-
b.Property("Slug")
.IsRequired()
.HasColumnType("text")
@@ -495,10 +273,6 @@ namespace Kyoo.Postgresql.Migrations
.HasColumnName("id")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
- b.Property("ForPeople")
- .HasColumnType("boolean")
- .HasColumnName("for_people");
-
b.Property("PeopleID")
.HasColumnType("integer")
.HasColumnName("people_id");
@@ -535,13 +309,9 @@ namespace Kyoo.Postgresql.Migrations
.HasColumnName("id")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
- b.Property("Logo")
- .HasColumnType("text")
- .HasColumnName("logo");
-
- b.Property("LogoExtension")
- .HasColumnType("text")
- .HasColumnName("logo_extension");
+ b.Property>("Images")
+ .HasColumnType("jsonb")
+ .HasColumnName("images");
b.Property("Name")
.HasColumnType("text")
@@ -574,14 +344,14 @@ namespace Kyoo.Postgresql.Migrations
.HasColumnType("timestamp without time zone")
.HasColumnName("end_date");
+ b.Property>("Images")
+ .HasColumnType("jsonb")
+ .HasColumnName("images");
+
b.Property("Overview")
.HasColumnType("text")
.HasColumnName("overview");
- b.Property("Poster")
- .HasColumnType("text")
- .HasColumnName("poster");
-
b.Property("SeasonNumber")
.HasColumnType("integer")
.HasColumnName("season_number");
@@ -629,22 +399,18 @@ namespace Kyoo.Postgresql.Migrations
.HasColumnType("text[]")
.HasColumnName("aliases");
- b.Property("Backdrop")
- .HasColumnType("text")
- .HasColumnName("backdrop");
-
b.Property("EndAir")
.HasColumnType("timestamp without time zone")
.HasColumnName("end_air");
+ b.Property>("Images")
+ .HasColumnType("jsonb")
+ .HasColumnName("images");
+
b.Property("IsMovie")
.HasColumnType("boolean")
.HasColumnName("is_movie");
- b.Property("Logo")
- .HasColumnType("text")
- .HasColumnName("logo");
-
b.Property("Overview")
.HasColumnType("text")
.HasColumnName("overview");
@@ -653,10 +419,6 @@ namespace Kyoo.Postgresql.Migrations
.HasColumnType("text")
.HasColumnName("path");
- b.Property("Poster")
- .HasColumnType("text")
- .HasColumnName("poster");
-
b.Property("Slug")
.IsRequired()
.HasColumnType("text")
@@ -678,10 +440,6 @@ namespace Kyoo.Postgresql.Migrations
.HasColumnType("text")
.HasColumnName("title");
- b.Property("TrailerUrl")
- .HasColumnType("text")
- .HasColumnName("trailer_url");
-
b.HasKey("ID")
.HasName("pk_shows");
@@ -805,6 +563,10 @@ namespace Kyoo.Postgresql.Migrations
.HasColumnType("jsonb")
.HasColumnName("extra_data");
+ b.Property>("Images")
+ .HasColumnType("jsonb")
+ .HasColumnName("images");
+
b.Property("Password")
.HasColumnType("text")
.HasColumnName("password");
@@ -834,27 +596,303 @@ namespace Kyoo.Postgresql.Migrations
modelBuilder.Entity("Kyoo.Models.WatchedEpisode", b =>
{
- b.Property("FirstID")
+ b.Property("UserID")
.HasColumnType("integer")
- .HasColumnName("first_id");
+ .HasColumnName("user_id");
- b.Property("SecondID")
+ b.Property("EpisodeID")
.HasColumnType("integer")
- .HasColumnName("second_id");
+ .HasColumnName("episode_id");
b.Property("WatchedPercentage")
.HasColumnType("integer")
.HasColumnName("watched_percentage");
- b.HasKey("FirstID", "SecondID")
+ b.HasKey("UserID", "EpisodeID")
.HasName("pk_watched_episodes");
- b.HasIndex("SecondID")
- .HasDatabaseName("ix_watched_episodes_second_id");
+ b.HasIndex("EpisodeID")
+ .HasDatabaseName("ix_watched_episodes_episode_id");
b.ToTable("watched_episodes");
});
+ modelBuilder.Entity("ShowUser", b =>
+ {
+ b.Property("UsersID")
+ .HasColumnType("integer")
+ .HasColumnName("users_id");
+
+ b.Property("WatchedID")
+ .HasColumnType("integer")
+ .HasColumnName("watched_id");
+
+ b.HasKey("UsersID", "WatchedID")
+ .HasName("pk_link_user_show");
+
+ b.HasIndex("WatchedID")
+ .HasDatabaseName("ix_link_user_show_watched_id");
+
+ b.ToTable("link_user_show");
+ });
+
+ modelBuilder.Entity("collection_metadata_id", b =>
+ {
+ b.Property("ResourceID")
+ .HasColumnType("integer")
+ .HasColumnName("resource_id");
+
+ b.Property("ProviderID")
+ .HasColumnType("integer")
+ .HasColumnName("provider_id");
+
+ b.Property("DataID")
+ .HasColumnType("text")
+ .HasColumnName("data_id");
+
+ b.Property("Link")
+ .HasColumnType("text")
+ .HasColumnName("link");
+
+ b.HasKey("ResourceID", "ProviderID")
+ .HasName("pk_collection_metadata_id");
+
+ b.HasIndex("ProviderID")
+ .HasDatabaseName("ix_collection_metadata_id_provider_id");
+
+ b.ToTable("collection_metadata_id");
+ });
+
+ modelBuilder.Entity("episode_metadata_id", b =>
+ {
+ b.Property("ResourceID")
+ .HasColumnType("integer")
+ .HasColumnName("resource_id");
+
+ b.Property("ProviderID")
+ .HasColumnType("integer")
+ .HasColumnName("provider_id");
+
+ b.Property("DataID")
+ .HasColumnType("text")
+ .HasColumnName("data_id");
+
+ b.Property("Link")
+ .HasColumnType("text")
+ .HasColumnName("link");
+
+ b.HasKey("ResourceID", "ProviderID")
+ .HasName("pk_episode_metadata_id");
+
+ b.HasIndex("ProviderID")
+ .HasDatabaseName("ix_episode_metadata_id_provider_id");
+
+ b.ToTable("episode_metadata_id");
+ });
+
+ modelBuilder.Entity("link_collection_show", b =>
+ {
+ b.Property("collection_id")
+ .HasColumnType("integer")
+ .HasColumnName("collection_id");
+
+ b.Property("show_id")
+ .HasColumnType("integer")
+ .HasColumnName("show_id");
+
+ b.HasKey("collection_id", "show_id")
+ .HasName("pk_link_collection_show");
+
+ b.HasIndex("show_id")
+ .HasDatabaseName("ix_link_collection_show_show_id");
+
+ b.ToTable("link_collection_show");
+ });
+
+ modelBuilder.Entity("link_library_collection", b =>
+ {
+ b.Property("collection_id")
+ .HasColumnType("integer")
+ .HasColumnName("collection_id");
+
+ b.Property("library_id")
+ .HasColumnType("integer")
+ .HasColumnName("library_id");
+
+ b.HasKey("collection_id", "library_id")
+ .HasName("pk_link_library_collection");
+
+ b.HasIndex("library_id")
+ .HasDatabaseName("ix_link_library_collection_library_id");
+
+ b.ToTable("link_library_collection");
+ });
+
+ modelBuilder.Entity("link_library_provider", b =>
+ {
+ b.Property("library_id")
+ .HasColumnType("integer")
+ .HasColumnName("library_id");
+
+ b.Property("provider_id")
+ .HasColumnType("integer")
+ .HasColumnName("provider_id");
+
+ b.HasKey("library_id", "provider_id")
+ .HasName("pk_link_library_provider");
+
+ b.HasIndex("provider_id")
+ .HasDatabaseName("ix_link_library_provider_provider_id");
+
+ b.ToTable("link_library_provider");
+ });
+
+ modelBuilder.Entity("link_library_show", b =>
+ {
+ b.Property("library_id")
+ .HasColumnType("integer")
+ .HasColumnName("library_id");
+
+ b.Property("show_id")
+ .HasColumnType("integer")
+ .HasColumnName("show_id");
+
+ b.HasKey("library_id", "show_id")
+ .HasName("pk_link_library_show");
+
+ b.HasIndex("show_id")
+ .HasDatabaseName("ix_link_library_show_show_id");
+
+ b.ToTable("link_library_show");
+ });
+
+ modelBuilder.Entity("link_show_genre", b =>
+ {
+ b.Property("genre_id")
+ .HasColumnType("integer")
+ .HasColumnName("genre_id");
+
+ b.Property("show_id")
+ .HasColumnType("integer")
+ .HasColumnName("show_id");
+
+ b.HasKey("genre_id", "show_id")
+ .HasName("pk_link_show_genre");
+
+ b.HasIndex("show_id")
+ .HasDatabaseName("ix_link_show_genre_show_id");
+
+ b.ToTable("link_show_genre");
+ });
+
+ modelBuilder.Entity("people_metadata_id", b =>
+ {
+ b.Property("ResourceID")
+ .HasColumnType("integer")
+ .HasColumnName("resource_id");
+
+ b.Property("ProviderID")
+ .HasColumnType("integer")
+ .HasColumnName("provider_id");
+
+ b.Property("DataID")
+ .HasColumnType("text")
+ .HasColumnName("data_id");
+
+ b.Property("Link")
+ .HasColumnType("text")
+ .HasColumnName("link");
+
+ b.HasKey("ResourceID", "ProviderID")
+ .HasName("pk_people_metadata_id");
+
+ b.HasIndex("ProviderID")
+ .HasDatabaseName("ix_people_metadata_id_provider_id");
+
+ b.ToTable("people_metadata_id");
+ });
+
+ modelBuilder.Entity("season_metadata_id", b =>
+ {
+ b.Property("ResourceID")
+ .HasColumnType("integer")
+ .HasColumnName("resource_id");
+
+ b.Property("ProviderID")
+ .HasColumnType("integer")
+ .HasColumnName("provider_id");
+
+ b.Property("DataID")
+ .HasColumnType("text")
+ .HasColumnName("data_id");
+
+ b.Property("Link")
+ .HasColumnType("text")
+ .HasColumnName("link");
+
+ b.HasKey("ResourceID", "ProviderID")
+ .HasName("pk_season_metadata_id");
+
+ b.HasIndex("ProviderID")
+ .HasDatabaseName("ix_season_metadata_id_provider_id");
+
+ b.ToTable("season_metadata_id");
+ });
+
+ modelBuilder.Entity("show_metadata_id", b =>
+ {
+ b.Property("ResourceID")
+ .HasColumnType("integer")
+ .HasColumnName("resource_id");
+
+ b.Property("ProviderID")
+ .HasColumnType("integer")
+ .HasColumnName("provider_id");
+
+ b.Property("DataID")
+ .HasColumnType("text")
+ .HasColumnName("data_id");
+
+ b.Property("Link")
+ .HasColumnType("text")
+ .HasColumnName("link");
+
+ b.HasKey("ResourceID", "ProviderID")
+ .HasName("pk_show_metadata_id");
+
+ b.HasIndex("ProviderID")
+ .HasDatabaseName("ix_show_metadata_id_provider_id");
+
+ b.ToTable("show_metadata_id");
+ });
+
+ modelBuilder.Entity("studio_metadata_id", b =>
+ {
+ b.Property("ResourceID")
+ .HasColumnType("integer")
+ .HasColumnName("resource_id");
+
+ b.Property("ProviderID")
+ .HasColumnType("integer")
+ .HasColumnName("provider_id");
+
+ b.Property("DataID")
+ .HasColumnType("text")
+ .HasColumnName("data_id");
+
+ b.Property("Link")
+ .HasColumnType("text")
+ .HasColumnName("link");
+
+ b.HasKey("ResourceID", "ProviderID")
+ .HasName("pk_studio_metadata_id");
+
+ b.HasIndex("ProviderID")
+ .HasDatabaseName("ix_studio_metadata_id_provider_id");
+
+ b.ToTable("studio_metadata_id");
+ });
+
modelBuilder.Entity("Kyoo.Models.Episode", b =>
{
b.HasOne("Kyoo.Models.Season", "Season")
@@ -875,216 +913,6 @@ namespace Kyoo.Postgresql.Migrations
b.Navigation("Show");
});
- modelBuilder.Entity("Kyoo.Models.Link", b =>
- {
- b.HasOne("Kyoo.Models.Collection", "First")
- .WithMany("ShowLinks")
- .HasForeignKey("FirstID")
- .HasConstraintName("fk_link_collection_show_collections_first_id")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b.HasOne("Kyoo.Models.Show", "Second")
- .WithMany("CollectionLinks")
- .HasForeignKey("SecondID")
- .HasConstraintName("fk_link_collection_show_shows_second_id")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b.Navigation("First");
-
- b.Navigation("Second");
- });
-
- modelBuilder.Entity("Kyoo.Models.Link", b =>
- {
- b.HasOne("Kyoo.Models.Library", "First")
- .WithMany("CollectionLinks")
- .HasForeignKey("FirstID")
- .HasConstraintName("fk_link_library_collection_libraries_first_id")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b.HasOne("Kyoo.Models.Collection", "Second")
- .WithMany("LibraryLinks")
- .HasForeignKey("SecondID")
- .HasConstraintName("fk_link_library_collection_collections_second_id")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b.Navigation("First");
-
- b.Navigation("Second");
- });
-
- modelBuilder.Entity("Kyoo.Models.Link", b =>
- {
- b.HasOne("Kyoo.Models.Library", "First")
- .WithMany("ProviderLinks")
- .HasForeignKey("FirstID")
- .HasConstraintName("fk_link_library_provider_libraries_first_id")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b.HasOne("Kyoo.Models.Provider", "Second")
- .WithMany("LibraryLinks")
- .HasForeignKey("SecondID")
- .HasConstraintName("fk_link_library_provider_providers_second_id")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b.Navigation("First");
-
- b.Navigation("Second");
- });
-
- modelBuilder.Entity("Kyoo.Models.Link", b =>
- {
- b.HasOne("Kyoo.Models.Library", "First")
- .WithMany("ShowLinks")
- .HasForeignKey("FirstID")
- .HasConstraintName("fk_link_library_show_libraries_first_id")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b.HasOne("Kyoo.Models.Show", "Second")
- .WithMany("LibraryLinks")
- .HasForeignKey("SecondID")
- .HasConstraintName("fk_link_library_show_shows_second_id")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b.Navigation("First");
-
- b.Navigation("Second");
- });
-
- modelBuilder.Entity("Kyoo.Models.Link", b =>
- {
- b.HasOne("Kyoo.Models.Show", "First")
- .WithMany("GenreLinks")
- .HasForeignKey("FirstID")
- .HasConstraintName("fk_link_show_genre_shows_first_id")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b.HasOne("Kyoo.Models.Genre", "Second")
- .WithMany("ShowLinks")
- .HasForeignKey("SecondID")
- .HasConstraintName("fk_link_show_genre_genres_second_id")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b.Navigation("First");
-
- b.Navigation("Second");
- });
-
- modelBuilder.Entity("Kyoo.Models.Link", b =>
- {
- b.HasOne("Kyoo.Models.User", "First")
- .WithMany("ShowLinks")
- .HasForeignKey("FirstID")
- .HasConstraintName("fk_link_user_show_users_first_id")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b.HasOne("Kyoo.Models.Show", "Second")
- .WithMany()
- .HasForeignKey("SecondID")
- .HasConstraintName("fk_link_user_show_shows_second_id")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b.Navigation("First");
-
- b.Navigation("Second");
- });
-
- modelBuilder.Entity("Kyoo.Models.MetadataID", b =>
- {
- b.HasOne("Kyoo.Models.Episode", "First")
- .WithMany("ExternalIDs")
- .HasForeignKey("FirstID")
- .HasConstraintName("fk_metadata_id_episode_episodes_first_id")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b.HasOne("Kyoo.Models.Provider", "Second")
- .WithMany()
- .HasForeignKey("SecondID")
- .HasConstraintName("fk_metadata_id_episode_providers_second_id")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b.Navigation("First");
-
- b.Navigation("Second");
- });
-
- modelBuilder.Entity("Kyoo.Models.MetadataID", b =>
- {
- b.HasOne("Kyoo.Models.People", "First")
- .WithMany("ExternalIDs")
- .HasForeignKey("FirstID")
- .HasConstraintName("fk_metadata_id_people_people_first_id")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b.HasOne("Kyoo.Models.Provider", "Second")
- .WithMany()
- .HasForeignKey("SecondID")
- .HasConstraintName("fk_metadata_id_people_providers_second_id")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b.Navigation("First");
-
- b.Navigation("Second");
- });
-
- modelBuilder.Entity("Kyoo.Models.MetadataID", b =>
- {
- b.HasOne("Kyoo.Models.Season", "First")
- .WithMany("ExternalIDs")
- .HasForeignKey("FirstID")
- .HasConstraintName("fk_metadata_id_season_seasons_first_id")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b.HasOne("Kyoo.Models.Provider", "Second")
- .WithMany()
- .HasForeignKey("SecondID")
- .HasConstraintName("fk_metadata_id_season_providers_second_id")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b.Navigation("First");
-
- b.Navigation("Second");
- });
-
- modelBuilder.Entity("Kyoo.Models.MetadataID", b =>
- {
- b.HasOne("Kyoo.Models.Show", "First")
- .WithMany("ExternalIDs")
- .HasForeignKey("FirstID")
- .HasConstraintName("fk_metadata_id_show_shows_first_id")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b.HasOne("Kyoo.Models.Provider", "Second")
- .WithMany()
- .HasForeignKey("SecondID")
- .HasConstraintName("fk_metadata_id_show_providers_second_id")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b.Navigation("First");
-
- b.Navigation("Second");
- });
-
modelBuilder.Entity("Kyoo.Models.PeopleRole", b =>
{
b.HasOne("Kyoo.Models.People", "People")
@@ -1143,30 +971,242 @@ namespace Kyoo.Postgresql.Migrations
modelBuilder.Entity("Kyoo.Models.WatchedEpisode", b =>
{
- b.HasOne("Kyoo.Models.User", "First")
- .WithMany("CurrentlyWatching")
- .HasForeignKey("FirstID")
- .HasConstraintName("fk_watched_episodes_users_first_id")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b.HasOne("Kyoo.Models.Episode", "Second")
+ b.HasOne("Kyoo.Models.Episode", "Episode")
.WithMany()
- .HasForeignKey("SecondID")
- .HasConstraintName("fk_watched_episodes_episodes_second_id")
+ .HasForeignKey("EpisodeID")
+ .HasConstraintName("fk_watched_episodes_episodes_episode_id")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
- b.Navigation("First");
+ b.HasOne("Kyoo.Models.User", null)
+ .WithMany("CurrentlyWatching")
+ .HasForeignKey("UserID")
+ .HasConstraintName("fk_watched_episodes_users_user_id")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
- b.Navigation("Second");
+ b.Navigation("Episode");
+ });
+
+ modelBuilder.Entity("ShowUser", b =>
+ {
+ b.HasOne("Kyoo.Models.User", null)
+ .WithMany()
+ .HasForeignKey("UsersID")
+ .HasConstraintName("fk_link_user_show_users_users_id")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Kyoo.Models.Show", null)
+ .WithMany()
+ .HasForeignKey("WatchedID")
+ .HasConstraintName("fk_link_user_show_shows_watched_id")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("collection_metadata_id", b =>
+ {
+ b.HasOne("Kyoo.Models.Provider", "Provider")
+ .WithMany()
+ .HasForeignKey("ProviderID")
+ .HasConstraintName("fk_collection_metadata_id_providers_provider_id")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Kyoo.Models.Collection", null)
+ .WithMany("ExternalIDs")
+ .HasForeignKey("ResourceID")
+ .HasConstraintName("fk_collection_metadata_id_collections_collection_id")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Provider");
+ });
+
+ modelBuilder.Entity("episode_metadata_id", b =>
+ {
+ b.HasOne("Kyoo.Models.Provider", "Provider")
+ .WithMany()
+ .HasForeignKey("ProviderID")
+ .HasConstraintName("fk_episode_metadata_id_providers_provider_id")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Kyoo.Models.Episode", null)
+ .WithMany("ExternalIDs")
+ .HasForeignKey("ResourceID")
+ .HasConstraintName("fk_episode_metadata_id_episodes_episode_id")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Provider");
+ });
+
+ modelBuilder.Entity("link_collection_show", b =>
+ {
+ b.HasOne("Kyoo.Models.Collection", null)
+ .WithMany()
+ .HasForeignKey("collection_id")
+ .HasConstraintName("fk_link_collection_show_collections_collection_id")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Kyoo.Models.Show", null)
+ .WithMany()
+ .HasForeignKey("show_id")
+ .HasConstraintName("fk_link_collection_show_shows_show_id")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("link_library_collection", b =>
+ {
+ b.HasOne("Kyoo.Models.Collection", null)
+ .WithMany()
+ .HasForeignKey("collection_id")
+ .HasConstraintName("fk_link_library_collection_collections_collection_id")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Kyoo.Models.Library", null)
+ .WithMany()
+ .HasForeignKey("library_id")
+ .HasConstraintName("fk_link_library_collection_libraries_library_id")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("link_library_provider", b =>
+ {
+ b.HasOne("Kyoo.Models.Library", null)
+ .WithMany()
+ .HasForeignKey("library_id")
+ .HasConstraintName("fk_link_library_provider_libraries_library_id")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Kyoo.Models.Provider", null)
+ .WithMany()
+ .HasForeignKey("provider_id")
+ .HasConstraintName("fk_link_library_provider_providers_provider_id")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("link_library_show", b =>
+ {
+ b.HasOne("Kyoo.Models.Library", null)
+ .WithMany()
+ .HasForeignKey("library_id")
+ .HasConstraintName("fk_link_library_show_libraries_library_id")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Kyoo.Models.Show", null)
+ .WithMany()
+ .HasForeignKey("show_id")
+ .HasConstraintName("fk_link_library_show_shows_show_id")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("link_show_genre", b =>
+ {
+ b.HasOne("Kyoo.Models.Genre", null)
+ .WithMany()
+ .HasForeignKey("genre_id")
+ .HasConstraintName("fk_link_show_genre_genres_genre_id")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Kyoo.Models.Show", null)
+ .WithMany()
+ .HasForeignKey("show_id")
+ .HasConstraintName("fk_link_show_genre_shows_show_id")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("people_metadata_id", b =>
+ {
+ b.HasOne("Kyoo.Models.Provider", "Provider")
+ .WithMany()
+ .HasForeignKey("ProviderID")
+ .HasConstraintName("fk_people_metadata_id_providers_provider_id")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Kyoo.Models.People", null)
+ .WithMany("ExternalIDs")
+ .HasForeignKey("ResourceID")
+ .HasConstraintName("fk_people_metadata_id_people_people_id")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Provider");
+ });
+
+ modelBuilder.Entity("season_metadata_id", b =>
+ {
+ b.HasOne("Kyoo.Models.Provider", "Provider")
+ .WithMany()
+ .HasForeignKey("ProviderID")
+ .HasConstraintName("fk_season_metadata_id_providers_provider_id")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Kyoo.Models.Season", null)
+ .WithMany("ExternalIDs")
+ .HasForeignKey("ResourceID")
+ .HasConstraintName("fk_season_metadata_id_seasons_season_id")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Provider");
+ });
+
+ modelBuilder.Entity("show_metadata_id", b =>
+ {
+ b.HasOne("Kyoo.Models.Provider", "Provider")
+ .WithMany()
+ .HasForeignKey("ProviderID")
+ .HasConstraintName("fk_show_metadata_id_providers_provider_id")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Kyoo.Models.Show", null)
+ .WithMany("ExternalIDs")
+ .HasForeignKey("ResourceID")
+ .HasConstraintName("fk_show_metadata_id_shows_show_id")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Provider");
+ });
+
+ modelBuilder.Entity("studio_metadata_id", b =>
+ {
+ b.HasOne("Kyoo.Models.Provider", "Provider")
+ .WithMany()
+ .HasForeignKey("ProviderID")
+ .HasConstraintName("fk_studio_metadata_id_providers_provider_id")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Kyoo.Models.Studio", null)
+ .WithMany("ExternalIDs")
+ .HasForeignKey("ResourceID")
+ .HasConstraintName("fk_studio_metadata_id_studios_studio_id")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Provider");
});
modelBuilder.Entity("Kyoo.Models.Collection", b =>
{
- b.Navigation("LibraryLinks");
-
- b.Navigation("ShowLinks");
+ b.Navigation("ExternalIDs");
});
modelBuilder.Entity("Kyoo.Models.Episode", b =>
@@ -1176,20 +1216,6 @@ namespace Kyoo.Postgresql.Migrations
b.Navigation("Tracks");
});
- modelBuilder.Entity("Kyoo.Models.Genre", b =>
- {
- b.Navigation("ShowLinks");
- });
-
- modelBuilder.Entity("Kyoo.Models.Library", b =>
- {
- b.Navigation("CollectionLinks");
-
- b.Navigation("ProviderLinks");
-
- b.Navigation("ShowLinks");
- });
-
modelBuilder.Entity("Kyoo.Models.People", b =>
{
b.Navigation("ExternalIDs");
@@ -1197,11 +1223,6 @@ namespace Kyoo.Postgresql.Migrations
b.Navigation("Roles");
});
- modelBuilder.Entity("Kyoo.Models.Provider", b =>
- {
- b.Navigation("LibraryLinks");
- });
-
modelBuilder.Entity("Kyoo.Models.Season", b =>
{
b.Navigation("Episodes");
@@ -1211,16 +1232,10 @@ namespace Kyoo.Postgresql.Migrations
modelBuilder.Entity("Kyoo.Models.Show", b =>
{
- b.Navigation("CollectionLinks");
-
b.Navigation("Episodes");
b.Navigation("ExternalIDs");
- b.Navigation("GenreLinks");
-
- b.Navigation("LibraryLinks");
-
b.Navigation("People");
b.Navigation("Seasons");
@@ -1228,14 +1243,14 @@ namespace Kyoo.Postgresql.Migrations
modelBuilder.Entity("Kyoo.Models.Studio", b =>
{
+ b.Navigation("ExternalIDs");
+
b.Navigation("Shows");
});
modelBuilder.Entity("Kyoo.Models.User", b =>
{
b.Navigation("CurrentlyWatching");
-
- b.Navigation("ShowLinks");
});
#pragma warning restore 612, 618
}
diff --git a/Kyoo.Postgresql/Migrations/20210723224326_Initial.cs b/Kyoo.Postgresql/Migrations/20210801171613_Initial.cs
similarity index 72%
rename from Kyoo.Postgresql/Migrations/20210723224326_Initial.cs
rename to Kyoo.Postgresql/Migrations/20210801171613_Initial.cs
index 2ba22c6a..395d9e27 100644
--- a/Kyoo.Postgresql/Migrations/20210723224326_Initial.cs
+++ b/Kyoo.Postgresql/Migrations/20210801171613_Initial.cs
@@ -23,7 +23,7 @@ namespace Kyoo.Postgresql.Migrations
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
slug = table.Column(type: "text", nullable: false),
name = table.Column(type: "text", nullable: true),
- poster = table.Column(type: "text", nullable: true),
+ images = table.Column>(type: "jsonb", nullable: true),
overview = table.Column(type: "text", nullable: true)
},
constraints: table =>
@@ -68,7 +68,7 @@ namespace Kyoo.Postgresql.Migrations
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
slug = table.Column(type: "text", nullable: false),
name = table.Column(type: "text", nullable: true),
- poster = table.Column(type: "text", nullable: true)
+ images = table.Column>(type: "jsonb", nullable: true)
},
constraints: table =>
{
@@ -83,8 +83,7 @@ namespace Kyoo.Postgresql.Migrations
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
slug = table.Column(type: "text", nullable: false),
name = table.Column(type: "text", nullable: true),
- logo = table.Column(type: "text", nullable: true),
- logo_extension = table.Column(type: "text", nullable: true)
+ images = table.Column>(type: "jsonb", nullable: true)
},
constraints: table =>
{
@@ -116,7 +115,8 @@ namespace Kyoo.Postgresql.Migrations
email = table.Column(type: "text", nullable: true),
password = table.Column(type: "text", nullable: true),
permissions = table.Column(type: "text[]", nullable: true),
- extra_data = table.Column>(type: "jsonb", nullable: true)
+ extra_data = table.Column>(type: "jsonb", nullable: true),
+ images = table.Column>(type: "jsonb", nullable: true)
},
constraints: table =>
{
@@ -127,71 +127,97 @@ namespace Kyoo.Postgresql.Migrations
name: "link_library_collection",
columns: table => new
{
- first_id = table.Column(type: "integer", nullable: false),
- second_id = table.Column(type: "integer", nullable: false)
+ collection_id = table.Column(type: "integer", nullable: false),
+ library_id = table.Column(type: "integer", nullable: false)
},
constraints: table =>
{
- table.PrimaryKey("pk_link_library_collection", x => new { x.first_id, x.second_id });
+ table.PrimaryKey("pk_link_library_collection", x => new { x.collection_id, x.library_id });
table.ForeignKey(
- name: "fk_link_library_collection_collections_second_id",
- column: x => x.second_id,
+ name: "fk_link_library_collection_collections_collection_id",
+ column: x => x.collection_id,
principalTable: "collections",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
- name: "fk_link_library_collection_libraries_first_id",
- column: x => x.first_id,
+ name: "fk_link_library_collection_libraries_library_id",
+ column: x => x.library_id,
principalTable: "libraries",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
});
+ migrationBuilder.CreateTable(
+ name: "collection_metadata_id",
+ columns: table => new
+ {
+ resource_id = table.Column(type: "integer", nullable: false),
+ provider_id = table.Column(type: "integer", nullable: false),
+ data_id = table.Column(type: "text", nullable: true),
+ link = table.Column(type: "text", nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("pk_collection_metadata_id", x => new { x.resource_id, x.provider_id });
+ table.ForeignKey(
+ name: "fk_collection_metadata_id_collections_collection_id",
+ column: x => x.resource_id,
+ principalTable: "collections",
+ principalColumn: "id",
+ onDelete: ReferentialAction.Cascade);
+ table.ForeignKey(
+ name: "fk_collection_metadata_id_providers_provider_id",
+ column: x => x.provider_id,
+ principalTable: "providers",
+ principalColumn: "id",
+ onDelete: ReferentialAction.Cascade);
+ });
+
migrationBuilder.CreateTable(
name: "link_library_provider",
columns: table => new
{
- first_id = table.Column(type: "integer", nullable: false),
- second_id = table.Column(type: "integer", nullable: false)
+ library_id = table.Column(type: "integer", nullable: false),
+ provider_id = table.Column(type: "integer", nullable: false)
},
constraints: table =>
{
- table.PrimaryKey("pk_link_library_provider", x => new { x.first_id, x.second_id });
+ table.PrimaryKey("pk_link_library_provider", x => new { x.library_id, x.provider_id });
table.ForeignKey(
- name: "fk_link_library_provider_libraries_first_id",
- column: x => x.first_id,
+ name: "fk_link_library_provider_libraries_library_id",
+ column: x => x.library_id,
principalTable: "libraries",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
- name: "fk_link_library_provider_providers_second_id",
- column: x => x.second_id,
+ name: "fk_link_library_provider_providers_provider_id",
+ column: x => x.provider_id,
principalTable: "providers",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
- name: "metadata_id_people",
+ name: "people_metadata_id",
columns: table => new
{
- first_id = table.Column(type: "integer", nullable: false),
- second_id = table.Column(type: "integer", nullable: false),
+ resource_id = table.Column(type: "integer", nullable: false),
+ provider_id = table.Column(type: "integer", nullable: false),
data_id = table.Column(type: "text", nullable: true),
link = table.Column(type: "text", nullable: true)
},
constraints: table =>
{
- table.PrimaryKey("pk_metadata_id_people", x => new { x.first_id, x.second_id });
+ table.PrimaryKey("pk_people_metadata_id", x => new { x.resource_id, x.provider_id });
table.ForeignKey(
- name: "fk_metadata_id_people_people_first_id",
- column: x => x.first_id,
+ name: "fk_people_metadata_id_people_people_id",
+ column: x => x.resource_id,
principalTable: "people",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
- name: "fk_metadata_id_people_providers_second_id",
- column: x => x.second_id,
+ name: "fk_people_metadata_id_providers_provider_id",
+ column: x => x.provider_id,
principalTable: "providers",
principalColumn: "id",
onDelete: ReferentialAction.Cascade);
@@ -209,12 +235,9 @@ namespace Kyoo.Postgresql.Migrations
path = table.Column(type: "text", nullable: true),
overview = table.Column(type: "text", nullable: true),
status = table.Column(type: "status", nullable: false),
- trailer_url = table.Column(type: "text", nullable: true),
start_air = table.Column(type: "timestamp without time zone", nullable: true),
end_air = table.Column(type: "timestamp without time zone", nullable: true),
- poster = table.Column(type: "text", nullable: true),
- logo = table.Column(type: "text", nullable: true),
- backdrop = table.Column(type: "text", nullable: true),
+ images = table.Column>(type: "jsonb", nullable: true),
is_movie = table.Column(type: "boolean", nullable: false),
studio_id = table.Column(type: "integer", nullable: true)
},
@@ -230,24 +253,50 @@ namespace Kyoo.Postgresql.Migrations
});
migrationBuilder.CreateTable(
- name: "link_collection_show",
+ name: "studio_metadata_id",
columns: table => new
{
- first_id = table.Column(type: "integer", nullable: false),
- second_id = table.Column(type: "integer", nullable: false)
+ resource_id = table.Column(type: "integer", nullable: false),
+ provider_id = table.Column(type: "integer", nullable: false),
+ data_id = table.Column(type: "text", nullable: true),
+ link = table.Column