mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-31 12:14:46 -04:00
Feat rework images, delete providers
This commit is contained in:
parent
e075306363
commit
386c6bf268
@ -85,11 +85,6 @@ namespace Kyoo.Abstractions.Controllers
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
IGenreRepository GenreRepository { get; }
|
IGenreRepository GenreRepository { get; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The repository that handle providers.
|
|
||||||
/// </summary>
|
|
||||||
IProviderRepository ProviderRepository { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The repository that handle users.
|
/// The repository that handle users.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -446,25 +446,6 @@ namespace Kyoo.Abstractions.Controllers
|
|||||||
Pagination limit = default);
|
Pagination limit = default);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A repository to handle providers.
|
|
||||||
/// </summary>
|
|
||||||
public interface IProviderRepository : IRepository<Provider>
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Get a list of external ids that match all filters
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="where">A predicate to add arbitrary filter</param>
|
|
||||||
/// <param name="sort">Sort information (sort order and sort by)</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>
|
|
||||||
/// <returns>A filtered list of external ids.</returns>
|
|
||||||
Task<ICollection<MetadataID>> GetMetadataID<T>(Expression<Func<MetadataID, bool>> where = null,
|
|
||||||
Sort<MetadataID> sort = default,
|
|
||||||
Pagination limit = default)
|
|
||||||
where T : class, IMetadata;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A repository to handle users.
|
/// A repository to handle users.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -35,22 +35,20 @@ namespace Kyoo.Abstractions.Controllers
|
|||||||
/// <param name="item">
|
/// <param name="item">
|
||||||
/// The item to cache images.
|
/// The item to cache images.
|
||||||
/// </param>
|
/// </param>
|
||||||
/// <param name="alwaysDownload">
|
|
||||||
/// <c>true</c> if images should be downloaded even if they already exists locally, <c>false</c> otherwise.
|
|
||||||
/// </param>
|
|
||||||
/// <typeparam name="T">The type of the item</typeparam>
|
/// <typeparam name="T">The type of the item</typeparam>
|
||||||
/// <returns><c>true</c> if an image has been downloaded, <c>false</c> otherwise.</returns>
|
/// <returns><c>true</c> if an image has been downloaded, <c>false</c> otherwise.</returns>
|
||||||
Task<bool> DownloadImages<T>(T item, bool alwaysDownload = false)
|
Task DownloadImages<T>(T item)
|
||||||
where T : IThumbnails;
|
where T : IThumbnails;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Retrieve the local path of an image of the given item.
|
/// Retrieve the local path of an image of the given item.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="item">The item to retrieve the poster from.</param>
|
/// <param name="item">The item to retrieve the poster from.</param>
|
||||||
/// <param name="imageId">The ID of the image. See <see cref="Images"/> for values.</param>
|
/// <param name="image">The ID of the image.</param>
|
||||||
|
/// <param name="quality">The quality of the image</param>
|
||||||
/// <typeparam name="T">The type of the item</typeparam>
|
/// <typeparam name="T">The type of the item</typeparam>
|
||||||
/// <returns>The path of the image for the given resource or null if it does not exists.</returns>
|
/// <returns>The path of the image for the given resource or null if it does not exists.</returns>
|
||||||
string? GetImagePath<T>(T item, int imageId)
|
string GetImagePath<T>(T item, string image, ImageQuality quality)
|
||||||
where T : IThumbnails;
|
where T : IThumbnails;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -85,7 +85,13 @@ namespace Kyoo.Abstractions.Models
|
|||||||
public DateTime? EndAir { get; set; }
|
public DateTime? EndAir { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public Dictionary<int, string> Images { get; set; }
|
public Image Poster { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Image Thumbnail { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Image Logo { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The type of this item (ether a collection, a show or a movie).
|
/// The type of this item (ether a collection, a show or a movie).
|
||||||
@ -110,7 +116,9 @@ namespace Kyoo.Abstractions.Models
|
|||||||
Status = show.Status;
|
Status = show.Status;
|
||||||
StartAir = show.StartAir;
|
StartAir = show.StartAir;
|
||||||
EndAir = show.EndAir;
|
EndAir = show.EndAir;
|
||||||
Images = show.Images;
|
Poster = show.Poster;
|
||||||
|
Thumbnail = show.Thumbnail;
|
||||||
|
Logo = show.Logo;
|
||||||
Type = show.IsMovie ? ItemType.Movie : ItemType.Show;
|
Type = show.IsMovie ? ItemType.Movie : ItemType.Show;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,7 +135,9 @@ namespace Kyoo.Abstractions.Models
|
|||||||
Status = Models.Status.Unknown;
|
Status = Models.Status.Unknown;
|
||||||
StartAir = null;
|
StartAir = null;
|
||||||
EndAir = null;
|
EndAir = null;
|
||||||
Images = collection.Images;
|
Poster = collection.Poster;
|
||||||
|
Thumbnail = collection.Thumbnail;
|
||||||
|
Logo = collection.Logo;
|
||||||
Type = ItemType.Collection;
|
Type = ItemType.Collection;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,7 +153,9 @@ namespace Kyoo.Abstractions.Models
|
|||||||
Status = x.Status,
|
Status = x.Status,
|
||||||
StartAir = x.StartAir,
|
StartAir = x.StartAir,
|
||||||
EndAir = x.EndAir,
|
EndAir = x.EndAir,
|
||||||
Images = x.Images,
|
Poster = x.Poster,
|
||||||
|
Thumbnail = x.Thumbnail,
|
||||||
|
Logo = x.Logo,
|
||||||
Type = x.IsMovie ? ItemType.Movie : ItemType.Show
|
Type = x.IsMovie ? ItemType.Movie : ItemType.Show
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -159,7 +171,9 @@ namespace Kyoo.Abstractions.Models
|
|||||||
Status = Models.Status.Unknown,
|
Status = Models.Status.Unknown,
|
||||||
StartAir = null,
|
StartAir = null,
|
||||||
EndAir = null,
|
EndAir = null,
|
||||||
Images = x.Images,
|
Poster = x.Poster,
|
||||||
|
Thumbnail = x.Thumbnail,
|
||||||
|
Logo = x.Logo,
|
||||||
Type = ItemType.Collection
|
Type = ItemType.Collection
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -14,11 +14,6 @@
|
|||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Linq.Expressions;
|
|
||||||
using Kyoo.Abstractions.Models.Attributes;
|
|
||||||
|
|
||||||
namespace Kyoo.Abstractions.Models
|
namespace Kyoo.Abstractions.Models
|
||||||
{
|
{
|
||||||
@ -27,29 +22,6 @@ namespace Kyoo.Abstractions.Models
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class MetadataID
|
public class MetadataID
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// The expression to retrieve the unique ID of a MetadataID. This is an aggregate of the two resources IDs.
|
|
||||||
/// </summary>
|
|
||||||
public static Expression<Func<MetadataID, object>> PrimaryKey
|
|
||||||
{
|
|
||||||
get { return x => new { First = x.ResourceID, Second = x.ProviderID }; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The ID of the resource which possess the metadata.
|
|
||||||
/// </summary>
|
|
||||||
[SerializeIgnore] public int ResourceID { 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>
|
||||||
|
@ -39,7 +39,13 @@ namespace Kyoo.Abstractions.Models
|
|||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public Dictionary<int, string> Images { get; set; }
|
public Image Poster { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Image Thumbnail { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Image Logo { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The description of this collection.
|
/// The description of this collection.
|
||||||
@ -57,6 +63,6 @@ namespace Kyoo.Abstractions.Models
|
|||||||
[LoadableRelation] public ICollection<Library> Libraries { get; set; }
|
[LoadableRelation] public ICollection<Library> Libraries { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[EditableRelation][LoadableRelation] public ICollection<MetadataID> ExternalIDs { get; set; }
|
public Dictionary<string, MetadataID> ExternalId { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -127,9 +127,6 @@ namespace Kyoo.Abstractions.Models
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string Path { get; set; }
|
public string Path { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public Dictionary<int, string> Images { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The title of this episode.
|
/// The title of this episode.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -146,7 +143,16 @@ namespace Kyoo.Abstractions.Models
|
|||||||
public DateTime? ReleaseDate { get; set; }
|
public DateTime? ReleaseDate { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[EditableRelation][LoadableRelation] public ICollection<MetadataID> ExternalIDs { get; set; }
|
public Image Poster { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Image Thumbnail { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Image Logo { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Dictionary<string, MetadataID> ExternalId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get the slug of an episode.
|
/// Get the slug of an episode.
|
||||||
|
@ -16,11 +16,7 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using JetBrains.Annotations;
|
|
||||||
using Kyoo.Abstractions.Models.Attributes;
|
|
||||||
|
|
||||||
namespace Kyoo.Abstractions.Models
|
namespace Kyoo.Abstractions.Models
|
||||||
{
|
{
|
||||||
@ -32,67 +28,6 @@ namespace Kyoo.Abstractions.Models
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The link to metadata providers that this show has. See <see cref="MetadataID"/> for more information.
|
/// The link to metadata providers that this show has. See <see cref="MetadataID"/> for more information.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[EditableRelation]
|
public Dictionary<string, MetadataID> ExternalId { get; set; }
|
||||||
[LoadableRelation]
|
|
||||||
public ICollection<MetadataID> ExternalIDs { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A static class containing extensions method for every <see cref="IMetadata"/> class.
|
|
||||||
/// This allow one to use metadata more easily.
|
|
||||||
/// </summary>
|
|
||||||
public static class MetadataExtension
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Retrieve the internal provider's ID of an item using it's provider slug.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// This method will never return anything if the <see cref="IMetadata.ExternalIDs"/> are not loaded.
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name="self">An instance of <see cref="IMetadata"/> to retrieve the ID from.</param>
|
|
||||||
/// <param name="provider">The slug of the provider</param>
|
|
||||||
/// <returns>The <see cref="MetadataID.DataID"/> field of the asked provider.</returns>
|
|
||||||
[CanBeNull]
|
|
||||||
public static string GetID(this IMetadata self, string provider)
|
|
||||||
{
|
|
||||||
return self.ExternalIDs?.FirstOrDefault(x => x.Provider.Slug == provider)?.DataID;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 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 <typeparamref name="T"/> type and <c>true</c> is returned.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// This method will never succeed if the <see cref="IMetadata.ExternalIDs"/> are not loaded.
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name="self">An instance of <see cref="IMetadata"/> to retrieve the ID from.</param>
|
|
||||||
/// <param name="provider">The slug of the provider</param>
|
|
||||||
/// <param name="id">
|
|
||||||
/// The <see cref="MetadataID.DataID"/> field of the asked provider parsed
|
|
||||||
/// and converted to the <typeparamref name="T"/> type.
|
|
||||||
/// It is only relevant if this method returns <c>true</c>.
|
|
||||||
/// </param>
|
|
||||||
/// <typeparam name="T">The type to convert the <see cref="MetadataID.DataID"/> to.</typeparam>
|
|
||||||
/// <returns><c>true</c> if this method succeeded, <c>false</c> otherwise.</returns>
|
|
||||||
public static bool TryGetID<T>(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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,8 +16,7 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using Kyoo.Abstractions.Controllers;
|
|
||||||
|
|
||||||
namespace Kyoo.Abstractions.Models
|
namespace Kyoo.Abstractions.Models
|
||||||
{
|
{
|
||||||
@ -25,53 +24,56 @@ namespace Kyoo.Abstractions.Models
|
|||||||
/// An interface representing items that contains images (like posters, thumbnails, logo, banners...)
|
/// An interface representing items that contains images (like posters, thumbnails, logo, banners...)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IThumbnails
|
public interface IThumbnails
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The list of images mapped to a certain index.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// An arbitrary index should not be used, instead use indexes from <see cref="Models.Images"/>
|
|
||||||
/// </remarks>
|
|
||||||
/// <example>{"0": "example.com/dune/poster"}</example>
|
|
||||||
public Dictionary<int, string> Images { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A class containing constant values for images. To be used as index of a <see cref="IThumbnails.Images"/>.
|
|
||||||
/// </summary>
|
|
||||||
public static class Images
|
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A poster is a 9/16 format image with the cover of the resource.
|
/// A poster is a 9/16 format image with the cover of the resource.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const int Poster = 0;
|
public Image Poster { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A thumbnail is a 16/9 format image, it could ether be used as a background or as a preview but it usually
|
/// 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.
|
/// is not an official image.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const int Thumbnail = 1;
|
public Image Thumbnail { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A logo is a small image representing the resource.
|
/// A logo is a small image representing the resource.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const int Logo = 2;
|
public Image Logo { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Image
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The original image from another server.
|
||||||
|
/// </summary>
|
||||||
|
public string Source { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A video of a few minutes that tease the content.
|
/// A hash to display as placeholder while the image is loading.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const int Trailer = 3;
|
[MaxLength(32)]
|
||||||
|
public string Blurhash { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The quality of an image
|
||||||
|
/// </summary>
|
||||||
|
public enum ImageQuality
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Small
|
||||||
|
/// </summary>
|
||||||
|
Small,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Retrieve the name of an image using it's ID. It is also used by the serializer to retrieve all named images.
|
/// Medium
|
||||||
/// If a plugin adds a new image type, it should add it's value and name here to allow the serializer to add it.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static Dictionary<int, string> ImageName { get; } = new()
|
Medium,
|
||||||
{
|
|
||||||
[Poster] = nameof(Poster),
|
/// <summary>
|
||||||
[Thumbnail] = nameof(Thumbnail),
|
/// Large
|
||||||
[Logo] = nameof(Logo),
|
/// </summary>
|
||||||
[Trailer] = nameof(Trailer)
|
Large,
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,11 +42,6 @@ namespace Kyoo.Abstractions.Models
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string[] Paths { get; set; }
|
public string[] Paths { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The list of <see cref="Provider"/> used for items in this library.
|
|
||||||
/// </summary>
|
|
||||||
[EditableRelation][LoadableRelation] public ICollection<Provider> Providers { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The list of shows in this library.
|
/// The list of shows in this library.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -38,10 +38,16 @@ namespace Kyoo.Abstractions.Models
|
|||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public Dictionary<int, string> Images { get; set; }
|
public Image Poster { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[EditableRelation][LoadableRelation] public ICollection<MetadataID> ExternalIDs { get; set; }
|
public Image Thumbnail { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Image Logo { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Dictionary<string, MetadataID> ExternalId { 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.
|
||||||
|
@ -1,71 +0,0 @@
|
|||||||
// Kyoo - A portable and vast media library solution.
|
|
||||||
// Copyright (c) Kyoo.
|
|
||||||
//
|
|
||||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
|
||||||
//
|
|
||||||
// Kyoo is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// any later version.
|
|
||||||
//
|
|
||||||
// Kyoo is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using Kyoo.Abstractions.Models.Attributes;
|
|
||||||
using Kyoo.Utils;
|
|
||||||
|
|
||||||
namespace Kyoo.Abstractions.Models
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A dead class that will be removed later.
|
|
||||||
/// </summary>
|
|
||||||
// TODO: Delete this class
|
|
||||||
public class Provider : IResource, IThumbnails
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
|
||||||
public int ID { get; set; }
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public string Slug { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The name of this provider.
|
|
||||||
/// </summary>
|
|
||||||
public string Name { get; set; }
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public Dictionary<int, string> Images { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The list of libraries that uses this provider.
|
|
||||||
/// </summary>
|
|
||||||
[LoadableRelation] public ICollection<Library> Libraries { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create a new, default, <see cref="Provider"/>
|
|
||||||
/// </summary>
|
|
||||||
public Provider() { }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create a new <see cref="Provider"/> and specify it's <see cref="Name"/>.
|
|
||||||
/// The <see cref="Slug"/> is automatically calculated from it's name.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="name">The name of this provider.</param>
|
|
||||||
/// <param name="logo">The logo of this provider.</param>
|
|
||||||
public Provider(string name, string logo)
|
|
||||||
{
|
|
||||||
Slug = Utility.ToSlug(name);
|
|
||||||
Name = name;
|
|
||||||
Images = new Dictionary<int, string>
|
|
||||||
{
|
|
||||||
[Models.Images.Logo] = logo
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -99,10 +99,16 @@ namespace Kyoo.Abstractions.Models
|
|||||||
public DateTime? EndDate { get; set; }
|
public DateTime? EndDate { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public Dictionary<int, string> Images { get; set; }
|
public Image Poster { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[EditableRelation][LoadableRelation] public ICollection<MetadataID> ExternalIDs { get; set; }
|
public Image Thumbnail { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Image Logo { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Dictionary<string, MetadataID> ExternalId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The list of episodes that this season contains.
|
/// The list of episodes that this season contains.
|
||||||
|
@ -59,13 +59,6 @@ namespace Kyoo.Abstractions.Models
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public Status Status { get; set; }
|
public Status Status { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// An URL to a trailer.
|
|
||||||
/// </summary>
|
|
||||||
/// TODO for now, this is set to a youtube url. It should be cached and converted to a local file.
|
|
||||||
[Obsolete("Use Images instead of this, this is only kept for the API response.")]
|
|
||||||
public string TrailerUrl => Images?.GetValueOrDefault(Models.Images.Trailer);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The date this show started airing. It can be null if this is unknown.
|
/// The date this show started airing. It can be null if this is unknown.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -78,16 +71,27 @@ namespace Kyoo.Abstractions.Models
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public DateTime? EndAir { get; set; }
|
public DateTime? EndAir { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public Dictionary<int, string> Images { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// True if this show represent a movie, false otherwise.
|
/// True if this show represent a movie, false otherwise.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsMovie { get; set; }
|
public bool IsMovie { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[EditableRelation][LoadableRelation] public ICollection<MetadataID> ExternalIDs { get; set; }
|
public Image Poster { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Image Thumbnail { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Image Logo { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A video of a few minutes that tease the content.
|
||||||
|
/// </summary>
|
||||||
|
public string Trailer { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Dictionary<string, MetadataID> ExternalId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The ID of the Studio that made this show.
|
/// The ID of the Studio that made this show.
|
||||||
|
@ -44,7 +44,7 @@ namespace Kyoo.Abstractions.Models
|
|||||||
[LoadableRelation] public ICollection<Show> Shows { get; set; }
|
[LoadableRelation] public ICollection<Show> Shows { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[EditableRelation][LoadableRelation] public ICollection<MetadataID> ExternalIDs { get; set; }
|
public Dictionary<string, MetadataID> ExternalId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a new, empty, <see cref="Studio"/>.
|
/// Create a new, empty, <see cref="Studio"/>.
|
||||||
|
@ -24,7 +24,7 @@ namespace Kyoo.Abstractions.Models
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// A single user of the app.
|
/// A single user of the app.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class User : IResource, IThumbnails
|
public class User : IResource
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public int ID { get; set; }
|
public int ID { get; set; }
|
||||||
@ -59,8 +59,10 @@ namespace Kyoo.Abstractions.Models
|
|||||||
[SerializeIgnore]
|
[SerializeIgnore]
|
||||||
public Dictionary<string, string> ExtraData { get; set; }
|
public Dictionary<string, string> ExtraData { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <summary>
|
||||||
public Dictionary<int, string> Images { get; set; }
|
/// A logo is a small image representing the resource.
|
||||||
|
/// </summary>
|
||||||
|
public Image Logo { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The list of shows the user has finished.
|
/// The list of shows the user has finished.
|
||||||
|
@ -103,7 +103,13 @@ namespace Kyoo.Abstractions.Models
|
|||||||
public bool IsMovie { get; set; }
|
public bool IsMovie { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public Dictionary<int, string> Images { get; set; }
|
public Image Poster { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Image Thumbnail { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Image Logo { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The transcoder's info for this item. This include subtitles, fonts, chapters...
|
/// The transcoder's info for this item. This include subtitles, fonts, chapters...
|
||||||
@ -145,7 +151,9 @@ namespace Kyoo.Abstractions.Models
|
|||||||
Title = ep.Title,
|
Title = ep.Title,
|
||||||
Overview = ep.Overview,
|
Overview = ep.Overview,
|
||||||
ReleaseDate = ep.ReleaseDate,
|
ReleaseDate = ep.ReleaseDate,
|
||||||
Images = ep.Show.Images,
|
Poster = ep.Poster,
|
||||||
|
Thumbnail = ep.Thumbnail,
|
||||||
|
Logo = ep.Logo,
|
||||||
PreviousEpisode = ep.Show.IsMovie
|
PreviousEpisode = ep.Show.IsMovie
|
||||||
? null
|
? null
|
||||||
: (await library.GetAll<Episode>(
|
: (await library.GetAll<Episode>(
|
||||||
|
@ -66,9 +66,6 @@ namespace Kyoo.Core.Controllers
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public IGenreRepository GenreRepository { get; }
|
public IGenreRepository GenreRepository { get; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public IProviderRepository ProviderRepository { get; }
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public IUserRepository UserRepository { get; }
|
public IUserRepository UserRepository { get; }
|
||||||
|
|
||||||
@ -89,7 +86,6 @@ namespace Kyoo.Core.Controllers
|
|||||||
PeopleRepository = GetRepository<People>() as IPeopleRepository;
|
PeopleRepository = GetRepository<People>() as IPeopleRepository;
|
||||||
StudioRepository = GetRepository<Studio>() as IStudioRepository;
|
StudioRepository = GetRepository<Studio>() as IStudioRepository;
|
||||||
GenreRepository = GetRepository<Genre>() as IGenreRepository;
|
GenreRepository = GetRepository<Genre>() as IGenreRepository;
|
||||||
ProviderRepository = GetRepository<Provider>() as IProviderRepository;
|
|
||||||
UserRepository = GetRepository<User>() as IUserRepository;
|
UserRepository = GetRepository<User>() as IUserRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -259,10 +255,6 @@ namespace Kyoo.Core.Controllers
|
|||||||
|
|
||||||
return (obj, member: memberName) switch
|
return (obj, member: memberName) switch
|
||||||
{
|
{
|
||||||
(Library l, nameof(Library.Providers)) => ProviderRepository
|
|
||||||
.GetAll(x => x.Libraries.Any(y => y.ID == obj.ID))
|
|
||||||
.Then(x => l.Providers = x),
|
|
||||||
|
|
||||||
(Library l, nameof(Library.Shows)) => ShowRepository
|
(Library l, nameof(Library.Shows)) => ShowRepository
|
||||||
.GetAll(x => x.Libraries.Any(y => y.ID == obj.ID))
|
.GetAll(x => x.Libraries.Any(y => y.ID == obj.ID))
|
||||||
.Then(x => l.Shows = x),
|
.Then(x => l.Shows = x),
|
||||||
@ -272,11 +264,6 @@ namespace Kyoo.Core.Controllers
|
|||||||
.Then(x => l.Collections = x),
|
.Then(x => l.Collections = x),
|
||||||
|
|
||||||
|
|
||||||
(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
|
(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),
|
||||||
@ -286,11 +273,6 @@ namespace Kyoo.Core.Controllers
|
|||||||
.Then(x => c.Libraries = x),
|
.Then(x => c.Libraries = x),
|
||||||
|
|
||||||
|
|
||||||
(Show s, nameof(Show.ExternalIDs)) => _SetRelation(s,
|
|
||||||
ProviderRepository.GetMetadataID<Show>(x => x.ResourceID == obj.ID),
|
|
||||||
(x, y) => x.ExternalIDs = y,
|
|
||||||
(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))
|
||||||
.Then(x => s.Genres = x),
|
.Then(x => s.Genres = x),
|
||||||
@ -326,11 +308,6 @@ namespace Kyoo.Core.Controllers
|
|||||||
}),
|
}),
|
||||||
|
|
||||||
|
|
||||||
(Season s, nameof(Season.ExternalIDs)) => _SetRelation(s,
|
|
||||||
ProviderRepository.GetMetadataID<Season>(x => x.ResourceID == obj.ID),
|
|
||||||
(x, y) => x.ExternalIDs = y,
|
|
||||||
(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),
|
||||||
(x, y) => x.Episodes = y,
|
(x, y) => x.Episodes = y,
|
||||||
@ -345,11 +322,6 @@ namespace Kyoo.Core.Controllers
|
|||||||
}),
|
}),
|
||||||
|
|
||||||
|
|
||||||
(Episode e, nameof(Episode.ExternalIDs)) => _SetRelation(e,
|
|
||||||
ProviderRepository.GetMetadataID<Episode>(x => x.ResourceID == obj.ID),
|
|
||||||
(x, y) => x.ExternalIDs = y,
|
|
||||||
(x, y) => { x.ResourceID = y.ID; }),
|
|
||||||
|
|
||||||
(Episode e, nameof(Episode.Show)) => ShowRepository
|
(Episode e, nameof(Episode.Show)) => ShowRepository
|
||||||
.GetOrDefault(x => x.Episodes.Any(y => y.ID == obj.ID))
|
.GetOrDefault(x => x.Episodes.Any(y => y.ID == obj.ID))
|
||||||
.Then(x =>
|
.Then(x =>
|
||||||
@ -376,27 +348,10 @@ namespace Kyoo.Core.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,
|
|
||||||
ProviderRepository.GetMetadataID<People>(x => x.ResourceID == obj.ID),
|
|
||||||
(x, y) => x.ExternalIDs = y,
|
|
||||||
(x, y) => { x.ResourceID = y.ID; }),
|
|
||||||
|
|
||||||
(People p, nameof(People.Roles)) => PeopleRepository
|
(People p, nameof(People.Roles)) => PeopleRepository
|
||||||
.GetFromPeople(obj.ID)
|
.GetFromPeople(obj.ID)
|
||||||
.Then(x => p.Roles = x),
|
.Then(x => p.Roles = x),
|
||||||
|
|
||||||
|
|
||||||
(Provider p, nameof(Provider.Libraries)) => LibraryRepository
|
|
||||||
.GetAll(x => x.Providers.Any(y => y.ID == obj.ID))
|
|
||||||
.Then(x => p.Libraries = x),
|
|
||||||
|
|
||||||
|
|
||||||
_ => throw new ArgumentException($"Couldn't find a way to load {memberName} of {obj.Slug}.")
|
_ => throw new ArgumentException($"Couldn't find a way to load {memberName} of {obj.Slug}.")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -37,11 +37,6 @@ namespace Kyoo.Core.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 Sort<Collection> DefaultSort => new Sort<Collection>.By(nameof(Collection.Name));
|
protected override Sort<Collection> DefaultSort => new Sort<Collection>.By(nameof(Collection.Name));
|
||||||
|
|
||||||
@ -49,12 +44,10 @@ namespace Kyoo.Core.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>
|
||||||
/// /// <param name="providers">A provider repository</param>
|
public CollectionRepository(DatabaseContext database)
|
||||||
public CollectionRepository(DatabaseContext database, IProviderRepository providers)
|
|
||||||
: base(database)
|
: base(database)
|
||||||
{
|
{
|
||||||
_database = database;
|
_database = database;
|
||||||
_providers = providers;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -82,33 +75,8 @@ namespace Kyoo.Core.Controllers
|
|||||||
{
|
{
|
||||||
await base.Validate(resource);
|
await base.Validate(resource);
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(resource.Slug))
|
|
||||||
throw new ArgumentException("The collection's slug must be set and not empty");
|
|
||||||
if (string.IsNullOrEmpty(resource.Name))
|
if (string.IsNullOrEmpty(resource.Name))
|
||||||
throw new ArgumentException("The collection's name must be set and not empty");
|
throw new ArgumentException("The collection's name must be set and not empty");
|
||||||
|
|
||||||
if (resource.ExternalIDs != null)
|
|
||||||
{
|
|
||||||
foreach (MetadataID id in resource.ExternalIDs)
|
|
||||||
{
|
|
||||||
id.Provider = _database.LocalEntity<Provider>(id.Provider.Slug)
|
|
||||||
?? await _providers.CreateIfNotExists(id.Provider);
|
|
||||||
id.ProviderID = id.Provider.ID;
|
|
||||||
}
|
|
||||||
_database.MetadataIds<Collection>().AttachRange(resource.ExternalIDs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
protected override async Task EditRelations(Collection resource, Collection changed, bool resetOld)
|
|
||||||
{
|
|
||||||
await Validate(changed);
|
|
||||||
|
|
||||||
if (changed.ExternalIDs != null || resetOld)
|
|
||||||
{
|
|
||||||
await Database.Entry(resource).Collection(x => x.ExternalIDs).LoadAsync();
|
|
||||||
resource.ExternalIDs = changed.ExternalIDs;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
@ -39,11 +39,6 @@ namespace Kyoo.Core.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;
|
|
||||||
|
|
||||||
private readonly IShowRepository _shows;
|
private readonly IShowRepository _shows;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -59,14 +54,11 @@ namespace Kyoo.Core.Controllers
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="database">The database handle to use.</param>
|
/// <param name="database">The database handle to use.</param>
|
||||||
/// <param name="shows">A show repository</param>
|
/// <param name="shows">A show repository</param>
|
||||||
/// <param name="providers">A provider repository</param>
|
|
||||||
public EpisodeRepository(DatabaseContext database,
|
public EpisodeRepository(DatabaseContext database,
|
||||||
IShowRepository shows,
|
IShowRepository shows)
|
||||||
IProviderRepository providers)
|
|
||||||
: base(database)
|
: base(database)
|
||||||
{
|
{
|
||||||
_database = database;
|
_database = database;
|
||||||
_providers = providers;
|
|
||||||
_shows = shows;
|
_shows = shows;
|
||||||
|
|
||||||
// Edit episode slugs when the show's slug changes.
|
// Edit episode slugs when the show's slug changes.
|
||||||
@ -160,18 +152,6 @@ namespace Kyoo.Core.Controllers
|
|||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
protected override async Task EditRelations(Episode resource, Episode changed, bool resetOld)
|
|
||||||
{
|
|
||||||
await Validate(changed);
|
|
||||||
|
|
||||||
if (changed.ExternalIDs != null || resetOld)
|
|
||||||
{
|
|
||||||
await Database.Entry(resource).Collection(x => x.ExternalIDs).LoadAsync();
|
|
||||||
resource.ExternalIDs = changed.ExternalIDs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override async Task Validate(Episode resource)
|
protected override async Task Validate(Episode resource)
|
||||||
{
|
{
|
||||||
@ -185,17 +165,6 @@ namespace Kyoo.Core.Controllers
|
|||||||
}
|
}
|
||||||
resource.ShowID = resource.Show.ID;
|
resource.ShowID = resource.Show.ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resource.ExternalIDs != null)
|
|
||||||
{
|
|
||||||
foreach (MetadataID id in resource.ExternalIDs)
|
|
||||||
{
|
|
||||||
id.Provider = _database.LocalEntity<Provider>(id.Provider.Slug)
|
|
||||||
?? await _providers.CreateIfNotExists(id.Provider);
|
|
||||||
id.ProviderID = id.Provider.ID;
|
|
||||||
}
|
|
||||||
_database.MetadataIds<Episode>().AttachRange(resource.ExternalIDs);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -206,7 +175,6 @@ namespace Kyoo.Core.Controllers
|
|||||||
|
|
||||||
int epCount = await _database.Episodes.Where(x => x.ShowID == obj.ShowID).Take(2).CountAsync();
|
int epCount = await _database.Episodes.Where(x => x.ShowID == obj.ShowID).Take(2).CountAsync();
|
||||||
_database.Entry(obj).State = EntityState.Deleted;
|
_database.Entry(obj).State = EntityState.Deleted;
|
||||||
obj.ExternalIDs.ForEach(x => _database.Entry(x).State = EntityState.Deleted);
|
|
||||||
await _database.SaveChangesAsync();
|
await _database.SaveChangesAsync();
|
||||||
await base.Delete(obj);
|
await base.Delete(obj);
|
||||||
if (epCount == 1)
|
if (epCount == 1)
|
||||||
|
@ -38,11 +38,6 @@ namespace Kyoo.Core.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 Sort<Library> DefaultSort => new Sort<Library>.By(x => x.ID);
|
protected override Sort<Library> DefaultSort => new Sort<Library>.By(x => x.ID);
|
||||||
|
|
||||||
@ -50,12 +45,10 @@ namespace Kyoo.Core.Controllers
|
|||||||
/// Create a new <see cref="LibraryRepository"/> instance.
|
/// Create a new <see cref="LibraryRepository"/> instance.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="database">The database handle</param>
|
/// <param name="database">The database handle</param>
|
||||||
/// <param name="providers">The provider repository</param>
|
public LibraryRepository(DatabaseContext database)
|
||||||
public LibraryRepository(DatabaseContext database, IProviderRepository providers)
|
|
||||||
: base(database)
|
: base(database)
|
||||||
{
|
{
|
||||||
_database = database;
|
_database = database;
|
||||||
_providers = providers;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -90,29 +83,6 @@ namespace Kyoo.Core.Controllers
|
|||||||
throw new ArgumentException("The library's name must be set and not empty");
|
throw new ArgumentException("The library's name must be set and not empty");
|
||||||
if (resource.Paths == null || !resource.Paths.Any())
|
if (resource.Paths == null || !resource.Paths.Any())
|
||||||
throw new ArgumentException("The library should have a least one path.");
|
throw new ArgumentException("The library should have a least one path.");
|
||||||
|
|
||||||
if (resource.Providers != null)
|
|
||||||
{
|
|
||||||
resource.Providers = await resource.Providers
|
|
||||||
.SelectAsync(async x =>
|
|
||||||
_database.LocalEntity<Provider>(x.Slug)
|
|
||||||
?? await _providers.CreateIfNotExists(x)
|
|
||||||
)
|
|
||||||
.ToListAsync();
|
|
||||||
_database.AttachRange(resource.Providers);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
protected override async Task EditRelations(Library resource, Library changed, bool resetOld)
|
|
||||||
{
|
|
||||||
await Validate(changed);
|
|
||||||
|
|
||||||
if (changed.Providers != null || resetOld)
|
|
||||||
{
|
|
||||||
await Database.Entry(resource).Collection(x => x.Providers).LoadAsync();
|
|
||||||
resource.Providers = changed.Providers;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
@ -341,6 +341,8 @@ namespace Kyoo.Core.Controllers
|
|||||||
if (obj == null)
|
if (obj == null)
|
||||||
throw new ArgumentNullException(nameof(obj));
|
throw new ArgumentNullException(nameof(obj));
|
||||||
await Validate(obj);
|
await Validate(obj);
|
||||||
|
// if (obj is IThumbnails thumbs)
|
||||||
|
// await _thumbnailsManager.DownloadImages(thumbs);
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,11 +39,6 @@ namespace Kyoo.Core.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;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A lazy loaded show repository to validate requests from shows.
|
/// A lazy loaded show repository to validate requests from shows.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -56,15 +51,12 @@ namespace Kyoo.Core.Controllers
|
|||||||
/// Create a new <see cref="PeopleRepository"/>
|
/// Create a new <see cref="PeopleRepository"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="database">The database handle</param>
|
/// <param name="database">The database handle</param>
|
||||||
/// <param name="providers">A provider repository</param>
|
|
||||||
/// <param name="shows">A lazy loaded show repository</param>
|
/// <param name="shows">A lazy loaded show repository</param>
|
||||||
public PeopleRepository(DatabaseContext database,
|
public PeopleRepository(DatabaseContext database,
|
||||||
IProviderRepository providers,
|
|
||||||
Lazy<IShowRepository> shows)
|
Lazy<IShowRepository> shows)
|
||||||
: base(database)
|
: base(database)
|
||||||
{
|
{
|
||||||
_database = database;
|
_database = database;
|
||||||
_providers = providers;
|
|
||||||
_shows = shows;
|
_shows = shows;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,17 +86,6 @@ namespace Kyoo.Core.Controllers
|
|||||||
{
|
{
|
||||||
await base.Validate(resource);
|
await base.Validate(resource);
|
||||||
|
|
||||||
if (resource.ExternalIDs != null)
|
|
||||||
{
|
|
||||||
foreach (MetadataID id in resource.ExternalIDs)
|
|
||||||
{
|
|
||||||
id.Provider = _database.LocalEntity<Provider>(id.Provider.Slug)
|
|
||||||
?? await _providers.CreateIfNotExists(id.Provider);
|
|
||||||
id.ProviderID = id.Provider.ID;
|
|
||||||
}
|
|
||||||
_database.MetadataIds<People>().AttachRange(resource.ExternalIDs);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (resource.Roles != null)
|
if (resource.Roles != null)
|
||||||
{
|
{
|
||||||
foreach (PeopleRole role in resource.Roles)
|
foreach (PeopleRole role in resource.Roles)
|
||||||
@ -127,12 +108,6 @@ namespace Kyoo.Core.Controllers
|
|||||||
await Database.Entry(resource).Collection(x => x.Roles).LoadAsync();
|
await Database.Entry(resource).Collection(x => x.Roles).LoadAsync();
|
||||||
resource.Roles = changed.Roles;
|
resource.Roles = changed.Roles;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (changed.ExternalIDs != null || resetOld)
|
|
||||||
{
|
|
||||||
await Database.Entry(resource).Collection(x => x.ExternalIDs).LoadAsync();
|
|
||||||
resource.ExternalIDs = changed.ExternalIDs;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -142,7 +117,6 @@ namespace Kyoo.Core.Controllers
|
|||||||
throw new ArgumentNullException(nameof(obj));
|
throw new ArgumentNullException(nameof(obj));
|
||||||
|
|
||||||
_database.Entry(obj).State = EntityState.Deleted;
|
_database.Entry(obj).State = EntityState.Deleted;
|
||||||
obj.ExternalIDs.ForEach(x => _database.Entry(x).State = EntityState.Deleted);
|
|
||||||
obj.Roles.ForEach(x => _database.Entry(x).State = EntityState.Deleted);
|
obj.Roles.ForEach(x => _database.Entry(x).State = EntityState.Deleted);
|
||||||
await _database.SaveChangesAsync();
|
await _database.SaveChangesAsync();
|
||||||
await base.Delete(obj);
|
await base.Delete(obj);
|
||||||
|
@ -1,98 +0,0 @@
|
|||||||
// Kyoo - A portable and vast media library solution.
|
|
||||||
// Copyright (c) Kyoo.
|
|
||||||
//
|
|
||||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
|
||||||
//
|
|
||||||
// Kyoo is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// any later version.
|
|
||||||
//
|
|
||||||
// Kyoo is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Linq.Expressions;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Kyoo.Abstractions.Controllers;
|
|
||||||
using Kyoo.Abstractions.Models;
|
|
||||||
using Kyoo.Postgresql;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
|
|
||||||
namespace Kyoo.Core.Controllers
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A local repository to handle providers.
|
|
||||||
/// </summary>
|
|
||||||
public class ProviderRepository : LocalRepository<Provider>, IProviderRepository
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The database handle
|
|
||||||
/// </summary>
|
|
||||||
private readonly DatabaseContext _database;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create a new <see cref="ProviderRepository" />.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="database">The database handle</param>
|
|
||||||
public ProviderRepository(DatabaseContext database)
|
|
||||||
: base(database)
|
|
||||||
{
|
|
||||||
_database = database;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
protected override Sort<Provider> DefaultSort => new Sort<Provider>.By(x => x.Slug);
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override async Task<ICollection<Provider>> Search(string query)
|
|
||||||
{
|
|
||||||
return await Sort(
|
|
||||||
_database.Providers
|
|
||||||
.Where(_database.Like<Provider>(x => x.Name, $"%{query}%"))
|
|
||||||
)
|
|
||||||
.Take(20)
|
|
||||||
.ToListAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override async Task<Provider> Create(Provider obj)
|
|
||||||
{
|
|
||||||
await base.Create(obj);
|
|
||||||
_database.Entry(obj).State = EntityState.Added;
|
|
||||||
await _database.SaveChangesAsync(() => Get(obj.Slug));
|
|
||||||
OnResourceCreated(obj);
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override async Task Delete(Provider obj)
|
|
||||||
{
|
|
||||||
if (obj == null)
|
|
||||||
throw new ArgumentNullException(nameof(obj));
|
|
||||||
|
|
||||||
_database.Entry(obj).State = EntityState.Deleted;
|
|
||||||
await _database.SaveChangesAsync();
|
|
||||||
await base.Delete(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public async Task<ICollection<MetadataID>> GetMetadataID<T>(Expression<Func<MetadataID, bool>> where = null,
|
|
||||||
Sort<MetadataID> sort = default,
|
|
||||||
Pagination limit = default)
|
|
||||||
where T : class, IMetadata
|
|
||||||
{
|
|
||||||
return await _database.MetadataIds<T>()
|
|
||||||
.Include(y => y.Provider)
|
|
||||||
.Where(where)
|
|
||||||
.ToListAsync();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -38,11 +38,6 @@ namespace Kyoo.Core.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 Sort<Season> DefaultSort => new Sort<Season>.By(x => x.SeasonNumber);
|
protected override Sort<Season> DefaultSort => new Sort<Season>.By(x => x.SeasonNumber);
|
||||||
|
|
||||||
@ -51,14 +46,11 @@ namespace Kyoo.Core.Controllers
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="database">The database handle that will be used</param>
|
/// <param name="database">The database handle that will be used</param>
|
||||||
/// <param name="shows">A shows repository</param>
|
/// <param name="shows">A shows repository</param>
|
||||||
/// <param name="providers">A provider repository</param>
|
|
||||||
public SeasonRepository(DatabaseContext database,
|
public SeasonRepository(DatabaseContext database,
|
||||||
IShowRepository shows,
|
IShowRepository shows)
|
||||||
IProviderRepository providers)
|
|
||||||
: base(database)
|
: base(database)
|
||||||
{
|
{
|
||||||
_database = database;
|
_database = database;
|
||||||
_providers = providers;
|
|
||||||
|
|
||||||
// Edit seasons slugs when the show's slug changes.
|
// Edit seasons slugs when the show's slug changes.
|
||||||
shows.OnEdited += (show) =>
|
shows.OnEdited += (show) =>
|
||||||
@ -140,29 +132,6 @@ namespace Kyoo.Core.Controllers
|
|||||||
}
|
}
|
||||||
resource.ShowID = resource.Show.ID;
|
resource.ShowID = resource.Show.ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resource.ExternalIDs != null)
|
|
||||||
{
|
|
||||||
foreach (MetadataID id in resource.ExternalIDs)
|
|
||||||
{
|
|
||||||
id.Provider = _database.LocalEntity<Provider>(id.Provider.Slug)
|
|
||||||
?? await _providers.CreateIfNotExists(id.Provider);
|
|
||||||
id.ProviderID = id.Provider.ID;
|
|
||||||
}
|
|
||||||
_database.MetadataIds<Season>().AttachRange(resource.ExternalIDs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
protected override async Task EditRelations(Season resource, Season changed, bool resetOld)
|
|
||||||
{
|
|
||||||
await Validate(changed);
|
|
||||||
|
|
||||||
if (changed.ExternalIDs != null || resetOld)
|
|
||||||
{
|
|
||||||
await Database.Entry(resource).Collection(x => x.ExternalIDs).LoadAsync();
|
|
||||||
resource.ExternalIDs = changed.ExternalIDs;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
|
@ -52,11 +52,6 @@ namespace Kyoo.Core.Controllers
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly IGenreRepository _genres;
|
private readonly IGenreRepository _genres;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A provider repository to handle externalID creation and deletion
|
|
||||||
/// </summary>
|
|
||||||
private readonly IProviderRepository _providers;
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override Sort<Show> DefaultSort => new Sort<Show>.By(x => x.Title);
|
protected override Sort<Show> DefaultSort => new Sort<Show>.By(x => x.Title);
|
||||||
|
|
||||||
@ -67,19 +62,16 @@ namespace Kyoo.Core.Controllers
|
|||||||
/// <param name="studios">A studio repository</param>
|
/// <param name="studios">A studio repository</param>
|
||||||
/// <param name="people">A people repository</param>
|
/// <param name="people">A people repository</param>
|
||||||
/// <param name="genres">A genres repository</param>
|
/// <param name="genres">A genres repository</param>
|
||||||
/// <param name="providers">A provider repository</param>
|
|
||||||
public ShowRepository(DatabaseContext database,
|
public ShowRepository(DatabaseContext database,
|
||||||
IStudioRepository studios,
|
IStudioRepository studios,
|
||||||
IPeopleRepository people,
|
IPeopleRepository people,
|
||||||
IGenreRepository genres,
|
IGenreRepository genres)
|
||||||
IProviderRepository providers)
|
|
||||||
: base(database)
|
: base(database)
|
||||||
{
|
{
|
||||||
_database = database;
|
_database = database;
|
||||||
_studios = studios;
|
_studios = studios;
|
||||||
_people = people;
|
_people = people;
|
||||||
_genres = genres;
|
_genres = genres;
|
||||||
_providers = providers;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -124,17 +116,6 @@ namespace Kyoo.Core.Controllers
|
|||||||
_database.AttachRange(resource.Genres);
|
_database.AttachRange(resource.Genres);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resource.ExternalIDs != null)
|
|
||||||
{
|
|
||||||
foreach (MetadataID id in resource.ExternalIDs)
|
|
||||||
{
|
|
||||||
id.Provider = _database.LocalEntity<Provider>(id.Provider.Slug)
|
|
||||||
?? await _providers.CreateIfNotExists(id.Provider);
|
|
||||||
id.ProviderID = id.Provider.ID;
|
|
||||||
}
|
|
||||||
_database.MetadataIds<Show>().AttachRange(resource.ExternalIDs);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (resource.People != null)
|
if (resource.People != null)
|
||||||
{
|
{
|
||||||
foreach (PeopleRole role in resource.People)
|
foreach (PeopleRole role in resource.People)
|
||||||
@ -172,12 +153,6 @@ namespace Kyoo.Core.Controllers
|
|||||||
await Database.Entry(resource).Collection(x => x.People).LoadAsync();
|
await Database.Entry(resource).Collection(x => x.People).LoadAsync();
|
||||||
resource.People = changed.People;
|
resource.People = changed.People;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (changed.ExternalIDs != null || resetOld)
|
|
||||||
{
|
|
||||||
await Database.Entry(resource).Collection(x => x.ExternalIDs).LoadAsync();
|
|
||||||
resource.ExternalIDs = changed.ExternalIDs;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
@ -38,11 +38,6 @@ namespace Kyoo.Core.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 Sort<Studio> DefaultSort => new Sort<Studio>.By(x => x.Name);
|
protected override Sort<Studio> DefaultSort => new Sort<Studio>.By(x => x.Name);
|
||||||
|
|
||||||
@ -50,12 +45,10 @@ namespace Kyoo.Core.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>
|
||||||
/// <param name="providers">A provider repository</param>
|
public StudioRepository(DatabaseContext database)
|
||||||
public StudioRepository(DatabaseContext database, IProviderRepository providers)
|
|
||||||
: base(database)
|
: base(database)
|
||||||
{
|
{
|
||||||
_database = database;
|
_database = database;
|
||||||
_providers = providers;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -83,30 +76,7 @@ namespace Kyoo.Core.Controllers
|
|||||||
protected override async Task Validate(Studio resource)
|
protected override async Task Validate(Studio resource)
|
||||||
{
|
{
|
||||||
resource.Slug ??= Utility.ToSlug(resource.Name);
|
resource.Slug ??= Utility.ToSlug(resource.Name);
|
||||||
|
|
||||||
await base.Validate(resource);
|
await base.Validate(resource);
|
||||||
if (resource.ExternalIDs != null)
|
|
||||||
{
|
|
||||||
foreach (MetadataID id in resource.ExternalIDs)
|
|
||||||
{
|
|
||||||
id.Provider = _database.LocalEntity<Provider>(id.Provider.Slug)
|
|
||||||
?? await _providers.CreateIfNotExists(id.Provider);
|
|
||||||
id.ProviderID = id.Provider.ID;
|
|
||||||
}
|
|
||||||
_database.MetadataIds<Studio>().AttachRange(resource.ExternalIDs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <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 />
|
||||||
|
@ -18,13 +18,12 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Kyoo.Abstractions.Controllers;
|
using Kyoo.Abstractions.Controllers;
|
||||||
using Kyoo.Abstractions.Models;
|
using Kyoo.Abstractions.Models;
|
||||||
using Microsoft.AspNetCore.StaticFiles;
|
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
using SkiaSharp;
|
||||||
|
|
||||||
#nullable enable
|
#nullable enable
|
||||||
|
|
||||||
@ -54,18 +53,18 @@ namespace Kyoo.Core.Controllers
|
|||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
private static async Task _WriteTo(SKBitmap bitmap, string path)
|
||||||
/// An helper function to download an image.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="url">The distant url of the image</param>
|
|
||||||
/// <param name="localPath">The local path of the image</param>
|
|
||||||
/// <param name="what">What is currently downloaded (used for errors)</param>
|
|
||||||
/// <returns><c>true</c> if an image has been downloaded, <c>false</c> otherwise.</returns>
|
|
||||||
private async Task<bool> _DownloadImage(string url, string localPath, string what)
|
|
||||||
{
|
{
|
||||||
if (url == localPath)
|
SKData data = bitmap.Encode(SKEncodedImageFormat.Jpeg, 18);
|
||||||
return false;
|
await using Stream reader = data.AsStream();
|
||||||
|
await using Stream file = File.Create(path);
|
||||||
|
await reader.CopyToAsync(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task _DownloadImage(string? url, string localPath, string what)
|
||||||
|
{
|
||||||
|
if (url == null)
|
||||||
|
return;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Downloading image {What}", what);
|
_logger.LogInformation("Downloading image {What}", what);
|
||||||
@ -73,86 +72,53 @@ namespace Kyoo.Core.Controllers
|
|||||||
HttpClient client = _clientFactory.CreateClient();
|
HttpClient client = _clientFactory.CreateClient();
|
||||||
HttpResponseMessage response = await client.GetAsync(url);
|
HttpResponseMessage response = await client.GetAsync(url);
|
||||||
response.EnsureSuccessStatusCode();
|
response.EnsureSuccessStatusCode();
|
||||||
string mime = response.Content.Headers.ContentType?.MediaType!;
|
|
||||||
await using Stream reader = await response.Content.ReadAsStreamAsync();
|
await using Stream reader = await response.Content.ReadAsStreamAsync();
|
||||||
|
SKBitmap bitmap = SKBitmap.Decode(reader);
|
||||||
|
|
||||||
string extension = new FileExtensionContentTypeProvider()
|
bitmap.Resize(new SKSizeI(bitmap.Width, bitmap.Height), SKFilterQuality.High);
|
||||||
.Mappings.FirstOrDefault(x => x.Value == mime)
|
await _WriteTo(bitmap, $"{localPath}.{ImageQuality.Large.ToString().ToLowerInvariant()}.jpg");
|
||||||
.Key;
|
|
||||||
await using Stream local = File.Create(localPath + extension);
|
bitmap.Resize(new SKSizeI(bitmap.Width, bitmap.Height), SKFilterQuality.Medium);
|
||||||
await reader.CopyToAsync(local);
|
await _WriteTo(bitmap, $"{localPath}.{ImageQuality.Medium.ToString().ToLowerInvariant()}.jpg");
|
||||||
return true;
|
|
||||||
|
bitmap.Resize(new SKSizeI(bitmap.Width, bitmap.Height), SKFilterQuality.Low);
|
||||||
|
await _WriteTo(bitmap, $"{localPath}.{ImageQuality.Small.ToString().ToLowerInvariant()}.jpg");
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.LogError(ex, "{What} could not be downloaded", what);
|
_logger.LogError(ex, "{What} could not be downloaded", what);
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public async Task<bool> DownloadImages<T>(T item, bool alwaysDownload = false)
|
public async Task DownloadImages<T>(T item)
|
||||||
where T : IThumbnails
|
where T : IThumbnails
|
||||||
{
|
{
|
||||||
if (item == null)
|
if (item == null)
|
||||||
throw new ArgumentNullException(nameof(item));
|
throw new ArgumentNullException(nameof(item));
|
||||||
|
|
||||||
if (item.Images == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
string name = item is IResource res ? res.Slug : "???";
|
string name = item is IResource res ? res.Slug : "???";
|
||||||
bool ret = false;
|
await _DownloadImage(item.Poster.Source, _GetBaseImagePath(item, "poster"), $"The poster of {name}");
|
||||||
|
await _DownloadImage(item.Thumbnail.Source, _GetBaseImagePath(item, "thumbnail"), $"The poster of {name}");
|
||||||
foreach ((int id, string image) in item.Images.Where(x => x.Value != null))
|
await _DownloadImage(item.Logo.Source, _GetBaseImagePath(item, "logo"), $"The poster of {name}");
|
||||||
{
|
|
||||||
string localPath = _GetPrivateImagePath(item, id);
|
|
||||||
if (alwaysDownload || !Path.Exists(localPath))
|
|
||||||
ret |= await _DownloadImage(image, localPath, $"The image n {id} of {name}");
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
private static string _GetBaseImagePath<T>(T item, string image)
|
||||||
/// Retrieve the local path of an image of the given item <b>without an extension</b>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="item">The item to retrieve the poster from.</param>
|
|
||||||
/// <param name="imageId">The ID of the image. See <see cref="Images"/> for values.</param>
|
|
||||||
/// <typeparam name="T">The type of the item</typeparam>
|
|
||||||
/// <returns>The path of the image for the given resource, <b>even if it does not exists</b></returns>
|
|
||||||
private static string _GetPrivateImagePath<T>(T item, int imageId)
|
|
||||||
{
|
{
|
||||||
if (item == null)
|
|
||||||
throw new ArgumentNullException(nameof(item));
|
|
||||||
|
|
||||||
string directory = item switch
|
string directory = item switch
|
||||||
{
|
{
|
||||||
IResource res => Path.Combine("./metadata", typeof(T).Name.ToLowerInvariant(), res.Slug),
|
IResource res => Path.Combine("./metadata", typeof(T).Name.ToLowerInvariant(), res.Slug),
|
||||||
_ => Path.Combine("./metadata", typeof(T).Name.ToLowerInvariant())
|
_ => Path.Combine("./metadata", typeof(T).Name.ToLowerInvariant())
|
||||||
};
|
};
|
||||||
Directory.CreateDirectory(directory);
|
Directory.CreateDirectory(directory);
|
||||||
string imageName = imageId switch
|
return Path.Combine(directory, image);
|
||||||
{
|
|
||||||
Images.Poster => "poster",
|
|
||||||
Images.Logo => "logo",
|
|
||||||
Images.Thumbnail => "thumbnail",
|
|
||||||
Images.Trailer => "trailer",
|
|
||||||
_ => $"{imageId}"
|
|
||||||
};
|
|
||||||
return Path.Combine(directory, imageName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public string? GetImagePath<T>(T item, int imageId)
|
public string GetImagePath<T>(T item, string image, ImageQuality quality)
|
||||||
where T : IThumbnails
|
where T : IThumbnails
|
||||||
{
|
{
|
||||||
string basePath = _GetPrivateImagePath(item, imageId);
|
return $"{_GetBaseImagePath(item, image)}.{quality.ToString().ToLowerInvariant()}.jpg";
|
||||||
string directory = Path.GetDirectoryName(basePath)!;
|
|
||||||
string baseFile = Path.GetFileName(basePath);
|
|
||||||
if (!Directory.Exists(directory))
|
|
||||||
return null;
|
|
||||||
return Directory.GetFiles(directory, "*", SearchOption.TopDirectoryOnly)
|
|
||||||
.FirstOrDefault(x => Path.GetFileNameWithoutExtension(x) == baseFile);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,6 @@ namespace Kyoo.Core
|
|||||||
builder.RegisterRepository<IPeopleRepository, PeopleRepository>();
|
builder.RegisterRepository<IPeopleRepository, PeopleRepository>();
|
||||||
builder.RegisterRepository<IStudioRepository, StudioRepository>();
|
builder.RegisterRepository<IStudioRepository, StudioRepository>();
|
||||||
builder.RegisterRepository<IGenreRepository, GenreRepository>();
|
builder.RegisterRepository<IGenreRepository, GenreRepository>();
|
||||||
builder.RegisterRepository<IProviderRepository, ProviderRepository>();
|
|
||||||
builder.RegisterRepository<IUserRepository, UserRepository>();
|
builder.RegisterRepository<IUserRepository, UserRepository>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,9 +6,11 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="AspNetCore.Proxy" Version="4.4.0" />
|
<PackageReference Include="AspNetCore.Proxy" Version="4.4.0" />
|
||||||
|
<PackageReference Include="BlurHashSharp.SkiaSharp" Version="1.3.0" />
|
||||||
<PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="5.2.9" />
|
<PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="5.2.9" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="7.0.9" />
|
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="7.0.9" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
|
<PackageReference Include="SkiaSharp" Version="2.88.3" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Kyoo.Abstractions.Controllers;
|
using Kyoo.Abstractions.Controllers;
|
||||||
@ -25,7 +24,6 @@ using Kyoo.Abstractions.Models.Permissions;
|
|||||||
using Kyoo.Abstractions.Models.Utils;
|
using Kyoo.Abstractions.Models.Utils;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.AspNetCore.StaticFiles;
|
|
||||||
using static Kyoo.Abstractions.Models.Utils.Constants;
|
using static Kyoo.Abstractions.Models.Utils.Constants;
|
||||||
|
|
||||||
namespace Kyoo.Core.Api
|
namespace Kyoo.Core.Api
|
||||||
@ -59,37 +57,7 @@ namespace Kyoo.Core.Api
|
|||||||
_thumbs = thumbs;
|
_thumbs = thumbs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
private async Task<IActionResult> _GetImage(Identifier identifier, string image, ImageQuality? quality)
|
||||||
/// Get the content type of a file using it's extension.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="path">The path of the file</param>
|
|
||||||
/// <exception cref="NotImplementedException">The extension of the file is not known.</exception>
|
|
||||||
/// <returns>The content type of the file</returns>
|
|
||||||
private static string _GetContentType(string path)
|
|
||||||
{
|
|
||||||
FileExtensionContentTypeProvider provider = new();
|
|
||||||
if (provider.TryGetContentType(path, out string contentType))
|
|
||||||
return contentType;
|
|
||||||
throw new NotImplementedException($"Can't get the content type of the file at: {path}");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get image
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Get an image for the specified item.
|
|
||||||
/// List of commonly available images:<br/>
|
|
||||||
/// - Poster: Image 0, also available at /poster<br/>
|
|
||||||
/// - Thumbnail: Image 1, also available at /thumbnail<br/>
|
|
||||||
/// - Logo: Image 3, also available at /logo<br/>
|
|
||||||
/// <br/>
|
|
||||||
/// Other images can be arbitrarily added by plugins so any image number can be specified from this endpoint.
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name="identifier">The ID or slug of the resource to get the image for.</param>
|
|
||||||
/// <param name="image">The number of the image to retrieve.</param>
|
|
||||||
/// <returns>The image asked.</returns>
|
|
||||||
/// <response code="404">No item exist with the specific identifier or the image does not exists on kyoo.</response>
|
|
||||||
private async Task<IActionResult> _GetImage(Identifier identifier, int image)
|
|
||||||
{
|
{
|
||||||
T resource = await identifier.Match(
|
T resource = await identifier.Match(
|
||||||
id => Repository.GetOrDefault(id),
|
id => Repository.GetOrDefault(id),
|
||||||
@ -97,10 +65,10 @@ namespace Kyoo.Core.Api
|
|||||||
);
|
);
|
||||||
if (resource == null)
|
if (resource == null)
|
||||||
return NotFound();
|
return NotFound();
|
||||||
string path = _thumbs.GetImagePath(resource, image);
|
string path = _thumbs.GetImagePath(resource, image, quality ?? ImageQuality.Large);
|
||||||
if (path == null || !System.IO.File.Exists(path))
|
if (path == null || !System.IO.File.Exists(path))
|
||||||
return NotFound();
|
return NotFound();
|
||||||
return PhysicalFile(Path.GetFullPath(path), _GetContentType(path), true);
|
return PhysicalFile(Path.GetFullPath(path), "image/jpeg", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -110,17 +78,18 @@ namespace Kyoo.Core.Api
|
|||||||
/// Get the poster for the specified item.
|
/// Get the poster for the specified item.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <param name="identifier">The ID or slug of the resource to get the image for.</param>
|
/// <param name="identifier">The ID or slug of the resource to get the image for.</param>
|
||||||
|
/// <param name="quality">The quality of the image to retrieve.</param>
|
||||||
/// <returns>The image asked.</returns>
|
/// <returns>The image asked.</returns>
|
||||||
/// <response code="404">
|
/// <response code="404">
|
||||||
/// No item exist with the specific identifier or the image does not exists on kyoo.
|
/// No item exist with the specific identifier or the image does not exists on kyoo.
|
||||||
/// </response>
|
/// </response>
|
||||||
[HttpGet("{identifier:id}/poster", Order = AlternativeRoute)]
|
[HttpGet("{identifier:id}/poster")]
|
||||||
[PartialPermission(Kind.Read)]
|
[PartialPermission(Kind.Read)]
|
||||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
public Task<IActionResult> GetPoster(Identifier identifier)
|
public Task<IActionResult> GetPoster(Identifier identifier, [FromQuery] ImageQuality? quality)
|
||||||
{
|
{
|
||||||
return _GetImage(identifier, Images.Poster);
|
return _GetImage(identifier, "poster", quality);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -130,17 +99,18 @@ namespace Kyoo.Core.Api
|
|||||||
/// Get the logo for the specified item.
|
/// Get the logo for the specified item.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <param name="identifier">The ID or slug of the resource to get the image for.</param>
|
/// <param name="identifier">The ID or slug of the resource to get the image for.</param>
|
||||||
|
/// <param name="quality">The quality of the image to retrieve.</param>
|
||||||
/// <returns>The image asked.</returns>
|
/// <returns>The image asked.</returns>
|
||||||
/// <response code="404">
|
/// <response code="404">
|
||||||
/// No item exist with the specific identifier or the image does not exists on kyoo.
|
/// No item exist with the specific identifier or the image does not exists on kyoo.
|
||||||
/// </response>
|
/// </response>
|
||||||
[HttpGet("{identifier:id}/logo", Order = AlternativeRoute)]
|
[HttpGet("{identifier:id}/logo")]
|
||||||
[PartialPermission(Kind.Read)]
|
[PartialPermission(Kind.Read)]
|
||||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
public Task<IActionResult> GetLogo(Identifier identifier)
|
public Task<IActionResult> GetLogo(Identifier identifier, [FromQuery] ImageQuality? quality)
|
||||||
{
|
{
|
||||||
return _GetImage(identifier, Images.Logo);
|
return _GetImage(identifier, "logo", quality);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -150,15 +120,16 @@ namespace Kyoo.Core.Api
|
|||||||
/// Get the thumbnail for the specified item.
|
/// Get the thumbnail for the specified item.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <param name="identifier">The ID or slug of the resource to get the image for.</param>
|
/// <param name="identifier">The ID or slug of the resource to get the image for.</param>
|
||||||
|
/// <param name="quality">The quality of the image to retrieve.</param>
|
||||||
/// <returns>The image asked.</returns>
|
/// <returns>The image asked.</returns>
|
||||||
/// <response code="404">
|
/// <response code="404">
|
||||||
/// No item exist with the specific identifier or the image does not exists on kyoo.
|
/// No item exist with the specific identifier or the image does not exists on kyoo.
|
||||||
/// </response>
|
/// </response>
|
||||||
|
[HttpGet("{identifier:id}/thumbnail")]
|
||||||
[HttpGet("{identifier:id}/backdrop", Order = AlternativeRoute)]
|
[HttpGet("{identifier:id}/backdrop", Order = AlternativeRoute)]
|
||||||
[HttpGet("{identifier:id}/thumbnail", Order = AlternativeRoute)]
|
public Task<IActionResult> GetBackdrop(Identifier identifier, [FromQuery] ImageQuality? quality)
|
||||||
public Task<IActionResult> GetBackdrop(Identifier identifier)
|
|
||||||
{
|
{
|
||||||
return _GetImage(identifier, Images.Thumbnail);
|
return _GetImage(identifier, "thumbnail", quality);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
|
@ -79,28 +79,28 @@ namespace Kyoo.Core.Api
|
|||||||
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
|
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
|
||||||
{
|
{
|
||||||
IList<JsonProperty> properties = base.CreateProperties(type, memberSerialization);
|
IList<JsonProperty> properties = base.CreateProperties(type, memberSerialization);
|
||||||
if (!type.IsAssignableTo(typeof(IThumbnails)))
|
if (!type.IsAssignableTo(typeof(Image)))
|
||||||
return properties;
|
return properties;
|
||||||
foreach ((int id, string image) in Images.ImageName)
|
// foreach ((int id, string image) in Images.ImageName)
|
||||||
{
|
// {
|
||||||
properties.Add(new JsonProperty
|
// properties.Add(new JsonProperty
|
||||||
{
|
// {
|
||||||
DeclaringType = type,
|
// DeclaringType = type,
|
||||||
PropertyName = image.ToLower(),
|
// PropertyName = image.ToLower(),
|
||||||
UnderlyingName = image,
|
// UnderlyingName = image,
|
||||||
PropertyType = typeof(string),
|
// PropertyType = typeof(string),
|
||||||
Readable = true,
|
// Readable = true,
|
||||||
Writable = false,
|
// Writable = false,
|
||||||
ItemIsReference = false,
|
// ItemIsReference = false,
|
||||||
TypeNameHandling = TypeNameHandling.None,
|
// TypeNameHandling = TypeNameHandling.None,
|
||||||
ShouldSerialize = x =>
|
// ShouldSerialize = x =>
|
||||||
{
|
// {
|
||||||
IThumbnails thumb = (IThumbnails)x;
|
// IThumbnails thumb = (IThumbnails)x;
|
||||||
return thumb?.Images?.ContainsKey(id) == true;
|
// return thumb?.Images?.ContainsKey(id) == true;
|
||||||
},
|
// },
|
||||||
ValueProvider = new ThumbnailProvider(id)
|
// ValueProvider = new ThumbnailProvider(id)
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
return properties;
|
return properties;
|
||||||
}
|
}
|
||||||
@ -128,23 +128,22 @@ namespace Kyoo.Core.Api
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void SetValue(object target, object value)
|
public void SetValue(object target, object value)
|
||||||
{
|
{
|
||||||
if (target is not IThumbnails thumb)
|
throw new NotSupportedException();
|
||||||
throw new ArgumentException($"The given object is not an Thumbnail.");
|
|
||||||
thumb.Images[_imageIndex] = value as string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public object GetValue(object target)
|
public object GetValue(object target)
|
||||||
{
|
{
|
||||||
string slug = (target as IResource)?.Slug ?? (target as ICustomTypeDescriptor)?.GetComponentName();
|
return null;
|
||||||
if (target is not IThumbnails thumb
|
// string slug = (target as IResource)?.Slug ?? (target as ICustomTypeDescriptor)?.GetComponentName();
|
||||||
|| slug == null
|
// if (target is not IThumbnails thumb
|
||||||
|| string.IsNullOrEmpty(thumb.Images?.GetValueOrDefault(_imageIndex)))
|
// || slug == null
|
||||||
return null;
|
// || string.IsNullOrEmpty(thumb.Images?.GetValueOrDefault(_imageIndex)))
|
||||||
string type = target is ICustomTypeDescriptor descriptor
|
// return null;
|
||||||
? descriptor.GetClassName()
|
// string type = target is ICustomTypeDescriptor descriptor
|
||||||
: target.GetType().Name;
|
// ? descriptor.GetClassName()
|
||||||
return $"/{type}/{slug}/{Images.ImageName[_imageIndex]}".ToLowerInvariant();
|
// : target.GetType().Name;
|
||||||
|
// return $"/{type}/{slug}/{Images.ImageName[_imageIndex]}".ToLowerInvariant();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Linq.Expressions;
|
using System.Linq.Expressions;
|
||||||
|
using System.Text.Json;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
@ -80,11 +81,6 @@ namespace Kyoo.Postgresql
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public DbSet<Studio> Studios { get; set; }
|
public DbSet<Studio> Studios { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// All providers of Kyoo. See <see cref="Provider"/>.
|
|
||||||
/// </summary>
|
|
||||||
public DbSet<Provider> Providers { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The list of registered users.
|
/// The list of registered users.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -108,17 +104,6 @@ namespace Kyoo.Postgresql
|
|||||||
/// </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"/>.
|
|
||||||
/// </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> MetadataIds<T>()
|
|
||||||
where T : class, IMetadata
|
|
||||||
{
|
|
||||||
return Set<MetadataID>(MetadataName<T>());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Add a many to many link between two resources.
|
/// Add a many to many link between two resources.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -194,17 +179,33 @@ namespace Kyoo.Postgresql
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="modelBuilder">The database model builder</param>
|
/// <param name="modelBuilder">The database model builder</param>
|
||||||
/// <typeparam name="T">The type to add metadata to.</typeparam>
|
/// <typeparam name="T">The type to add metadata to.</typeparam>
|
||||||
private void _HasMetadata<T>(ModelBuilder modelBuilder)
|
private static void _HasMetadata<T>(ModelBuilder modelBuilder)
|
||||||
where T : class, IMetadata
|
where T : class, IMetadata
|
||||||
{
|
{
|
||||||
modelBuilder.SharedTypeEntity<MetadataID>(MetadataName<T>())
|
// TODO: Waiting for https://github.com/dotnet/efcore/issues/29825
|
||||||
.HasKey(MetadataID.PrimaryKey);
|
// modelBuilder.Entity<T>()
|
||||||
|
// .OwnsOne(x => x.ExternalIDs, x =>
|
||||||
|
// {
|
||||||
|
// x.ToJson();
|
||||||
|
// });
|
||||||
|
modelBuilder.Entity<T>()
|
||||||
|
.Property(x => x.ExternalId)
|
||||||
|
.HasConversion(
|
||||||
|
v => JsonSerializer.Serialize(v, (JsonSerializerOptions)null),
|
||||||
|
v => JsonSerializer.Deserialize<Dictionary<string, MetadataID>>(v, (JsonSerializerOptions)null)
|
||||||
|
)
|
||||||
|
.HasColumnType("json");
|
||||||
|
}
|
||||||
|
|
||||||
modelBuilder.SharedTypeEntity<MetadataID>(MetadataName<T>())
|
private static void _HasImages<T>(ModelBuilder modelBuilder)
|
||||||
.HasOne<T>()
|
where T : class, IThumbnails
|
||||||
.WithMany(x => x.ExternalIDs)
|
{
|
||||||
.HasForeignKey(x => x.ResourceID)
|
modelBuilder.Entity<T>()
|
||||||
.OnDelete(DeleteBehavior.Cascade);
|
.OwnsOne(x => x.Poster);
|
||||||
|
modelBuilder.Entity<T>()
|
||||||
|
.OwnsOne(x => x.Thumbnail);
|
||||||
|
modelBuilder.Entity<T>()
|
||||||
|
.OwnsOne(x => x.Logo);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -269,7 +270,6 @@ namespace Kyoo.Postgresql
|
|||||||
.WithMany(x => x.Shows)
|
.WithMany(x => x.Shows)
|
||||||
.OnDelete(DeleteBehavior.SetNull);
|
.OnDelete(DeleteBehavior.SetNull);
|
||||||
|
|
||||||
_HasManyToMany<Library, Provider>(modelBuilder, x => x.Providers, x => x.Libraries);
|
|
||||||
_HasManyToMany<Library, Collection>(modelBuilder, x => x.Collections, x => x.Libraries);
|
_HasManyToMany<Library, Collection>(modelBuilder, x => x.Collections, x => x.Libraries);
|
||||||
_HasManyToMany<Library, Show>(modelBuilder, x => x.Shows, x => x.Libraries);
|
_HasManyToMany<Library, Show>(modelBuilder, x => x.Shows, x => x.Libraries);
|
||||||
_HasManyToMany<Collection, Show>(modelBuilder, x => x.Shows, x => x.Collections);
|
_HasManyToMany<Collection, Show>(modelBuilder, x => x.Shows, x => x.Collections);
|
||||||
@ -287,6 +287,15 @@ namespace Kyoo.Postgresql
|
|||||||
_HasMetadata<People>(modelBuilder);
|
_HasMetadata<People>(modelBuilder);
|
||||||
_HasMetadata<Studio>(modelBuilder);
|
_HasMetadata<Studio>(modelBuilder);
|
||||||
|
|
||||||
|
_HasImages<LibraryItem>(modelBuilder);
|
||||||
|
_HasImages<Collection>(modelBuilder);
|
||||||
|
_HasImages<Show>(modelBuilder);
|
||||||
|
_HasImages<Season>(modelBuilder);
|
||||||
|
_HasImages<Episode>(modelBuilder);
|
||||||
|
_HasImages<People>(modelBuilder);
|
||||||
|
|
||||||
|
modelBuilder.Entity<User>().OwnsOne(x => x.Logo);
|
||||||
|
|
||||||
modelBuilder.Entity<WatchedEpisode>()
|
modelBuilder.Entity<WatchedEpisode>()
|
||||||
.HasKey(x => new { User = x.UserID, Episode = x.EpisodeID });
|
.HasKey(x => new { User = x.UserID, Episode = x.EpisodeID });
|
||||||
|
|
||||||
@ -294,7 +303,6 @@ namespace Kyoo.Postgresql
|
|||||||
modelBuilder.Entity<Genre>().Property(x => x.Slug).IsRequired();
|
modelBuilder.Entity<Genre>().Property(x => x.Slug).IsRequired();
|
||||||
modelBuilder.Entity<Library>().Property(x => x.Slug).IsRequired();
|
modelBuilder.Entity<Library>().Property(x => x.Slug).IsRequired();
|
||||||
modelBuilder.Entity<People>().Property(x => x.Slug).IsRequired();
|
modelBuilder.Entity<People>().Property(x => x.Slug).IsRequired();
|
||||||
modelBuilder.Entity<Provider>().Property(x => x.Slug).IsRequired();
|
|
||||||
modelBuilder.Entity<Show>().Property(x => x.Slug).IsRequired();
|
modelBuilder.Entity<Show>().Property(x => x.Slug).IsRequired();
|
||||||
modelBuilder.Entity<Season>().Property(x => x.Slug).IsRequired();
|
modelBuilder.Entity<Season>().Property(x => x.Slug).IsRequired();
|
||||||
modelBuilder.Entity<Episode>().Property(x => x.Slug).IsRequired();
|
modelBuilder.Entity<Episode>().Property(x => x.Slug).IsRequired();
|
||||||
@ -319,9 +327,6 @@ namespace Kyoo.Postgresql
|
|||||||
modelBuilder.Entity<Studio>()
|
modelBuilder.Entity<Studio>()
|
||||||
.HasIndex(x => x.Slug)
|
.HasIndex(x => x.Slug)
|
||||||
.IsUnique();
|
.IsUnique();
|
||||||
modelBuilder.Entity<Provider>()
|
|
||||||
.HasIndex(x => x.Slug)
|
|
||||||
.IsUnique();
|
|
||||||
modelBuilder.Entity<Season>()
|
modelBuilder.Entity<Season>()
|
||||||
.HasIndex(x => new { x.ShowID, x.SeasonNumber })
|
.HasIndex(x => new { x.ShowID, x.SeasonNumber })
|
||||||
.IsUnique();
|
.IsUnique();
|
||||||
|
1339
back/src/Kyoo.Postgresql/Migrations/20230804143919_AddBlurhash.Designer.cs
generated
Normal file
1339
back/src/Kyoo.Postgresql/Migrations/20230804143919_AddBlurhash.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,772 @@
|
|||||||
|
// Kyoo - A portable and vast media library solution.
|
||||||
|
// Copyright (c) Kyoo.
|
||||||
|
//
|
||||||
|
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||||
|
//
|
||||||
|
// Kyoo is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// any later version.
|
||||||
|
//
|
||||||
|
// Kyoo is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Kyoo.Postgresql.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddBlurhash : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
MigrationHelper.DropLibraryItemsView(migrationBuilder);
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "collection_metadata_id");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "episode_metadata_id");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "link_library_provider");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "people_metadata_id");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "season_metadata_id");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "show_metadata_id");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "studio_metadata_id");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "providers");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "images",
|
||||||
|
table: "users");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "images",
|
||||||
|
table: "shows");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "images",
|
||||||
|
table: "seasons");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "images",
|
||||||
|
table: "people");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "images",
|
||||||
|
table: "episodes");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "images",
|
||||||
|
table: "collections");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "logo_blurhash",
|
||||||
|
table: "users",
|
||||||
|
type: "character varying(32)",
|
||||||
|
maxLength: 32,
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "logo_source",
|
||||||
|
table: "users",
|
||||||
|
type: "text",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "external_id",
|
||||||
|
table: "studios",
|
||||||
|
type: "json",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "external_id",
|
||||||
|
table: "shows",
|
||||||
|
type: "json",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "logo_blurhash",
|
||||||
|
table: "shows",
|
||||||
|
type: "character varying(32)",
|
||||||
|
maxLength: 32,
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "logo_source",
|
||||||
|
table: "shows",
|
||||||
|
type: "text",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "poster_blurhash",
|
||||||
|
table: "shows",
|
||||||
|
type: "character varying(32)",
|
||||||
|
maxLength: 32,
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "poster_source",
|
||||||
|
table: "shows",
|
||||||
|
type: "text",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "thumbnail_blurhash",
|
||||||
|
table: "shows",
|
||||||
|
type: "character varying(32)",
|
||||||
|
maxLength: 32,
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "thumbnail_source",
|
||||||
|
table: "shows",
|
||||||
|
type: "text",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "trailer",
|
||||||
|
table: "shows",
|
||||||
|
type: "text",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "external_id",
|
||||||
|
table: "seasons",
|
||||||
|
type: "json",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "logo_blurhash",
|
||||||
|
table: "seasons",
|
||||||
|
type: "character varying(32)",
|
||||||
|
maxLength: 32,
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "logo_source",
|
||||||
|
table: "seasons",
|
||||||
|
type: "text",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "poster_blurhash",
|
||||||
|
table: "seasons",
|
||||||
|
type: "character varying(32)",
|
||||||
|
maxLength: 32,
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "poster_source",
|
||||||
|
table: "seasons",
|
||||||
|
type: "text",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "thumbnail_blurhash",
|
||||||
|
table: "seasons",
|
||||||
|
type: "character varying(32)",
|
||||||
|
maxLength: 32,
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "thumbnail_source",
|
||||||
|
table: "seasons",
|
||||||
|
type: "text",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "external_id",
|
||||||
|
table: "people",
|
||||||
|
type: "json",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "logo_blurhash",
|
||||||
|
table: "people",
|
||||||
|
type: "character varying(32)",
|
||||||
|
maxLength: 32,
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "logo_source",
|
||||||
|
table: "people",
|
||||||
|
type: "text",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "poster_blurhash",
|
||||||
|
table: "people",
|
||||||
|
type: "character varying(32)",
|
||||||
|
maxLength: 32,
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "poster_source",
|
||||||
|
table: "people",
|
||||||
|
type: "text",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "thumbnail_blurhash",
|
||||||
|
table: "people",
|
||||||
|
type: "character varying(32)",
|
||||||
|
maxLength: 32,
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "thumbnail_source",
|
||||||
|
table: "people",
|
||||||
|
type: "text",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "external_id",
|
||||||
|
table: "episodes",
|
||||||
|
type: "json",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "logo_blurhash",
|
||||||
|
table: "episodes",
|
||||||
|
type: "character varying(32)",
|
||||||
|
maxLength: 32,
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "logo_source",
|
||||||
|
table: "episodes",
|
||||||
|
type: "text",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "poster_blurhash",
|
||||||
|
table: "episodes",
|
||||||
|
type: "character varying(32)",
|
||||||
|
maxLength: 32,
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "poster_source",
|
||||||
|
table: "episodes",
|
||||||
|
type: "text",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "thumbnail_blurhash",
|
||||||
|
table: "episodes",
|
||||||
|
type: "character varying(32)",
|
||||||
|
maxLength: 32,
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "thumbnail_source",
|
||||||
|
table: "episodes",
|
||||||
|
type: "text",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "external_id",
|
||||||
|
table: "collections",
|
||||||
|
type: "json",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "logo_blurhash",
|
||||||
|
table: "collections",
|
||||||
|
type: "character varying(32)",
|
||||||
|
maxLength: 32,
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "logo_source",
|
||||||
|
table: "collections",
|
||||||
|
type: "text",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "poster_blurhash",
|
||||||
|
table: "collections",
|
||||||
|
type: "character varying(32)",
|
||||||
|
maxLength: 32,
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "poster_source",
|
||||||
|
table: "collections",
|
||||||
|
type: "text",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "thumbnail_blurhash",
|
||||||
|
table: "collections",
|
||||||
|
type: "character varying(32)",
|
||||||
|
maxLength: 32,
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "thumbnail_source",
|
||||||
|
table: "collections",
|
||||||
|
type: "text",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
MigrationHelper.CreateLibraryItemsView(migrationBuilder);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
MigrationHelper.DropLibraryItemsView(migrationBuilder);
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "logo_blurhash",
|
||||||
|
table: "users");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "logo_source",
|
||||||
|
table: "users");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "external_id",
|
||||||
|
table: "studios");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "external_id",
|
||||||
|
table: "shows");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "logo_blurhash",
|
||||||
|
table: "shows");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "logo_source",
|
||||||
|
table: "shows");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "poster_blurhash",
|
||||||
|
table: "shows");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "poster_source",
|
||||||
|
table: "shows");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "thumbnail_blurhash",
|
||||||
|
table: "shows");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "thumbnail_source",
|
||||||
|
table: "shows");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "trailer",
|
||||||
|
table: "shows");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "external_id",
|
||||||
|
table: "seasons");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "logo_blurhash",
|
||||||
|
table: "seasons");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "logo_source",
|
||||||
|
table: "seasons");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "poster_blurhash",
|
||||||
|
table: "seasons");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "poster_source",
|
||||||
|
table: "seasons");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "thumbnail_blurhash",
|
||||||
|
table: "seasons");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "thumbnail_source",
|
||||||
|
table: "seasons");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "external_id",
|
||||||
|
table: "people");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "logo_blurhash",
|
||||||
|
table: "people");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "logo_source",
|
||||||
|
table: "people");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "poster_blurhash",
|
||||||
|
table: "people");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "poster_source",
|
||||||
|
table: "people");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "thumbnail_blurhash",
|
||||||
|
table: "people");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "thumbnail_source",
|
||||||
|
table: "people");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "external_id",
|
||||||
|
table: "episodes");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "logo_blurhash",
|
||||||
|
table: "episodes");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "logo_source",
|
||||||
|
table: "episodes");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "poster_blurhash",
|
||||||
|
table: "episodes");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "poster_source",
|
||||||
|
table: "episodes");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "thumbnail_blurhash",
|
||||||
|
table: "episodes");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "thumbnail_source",
|
||||||
|
table: "episodes");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "external_id",
|
||||||
|
table: "collections");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "logo_blurhash",
|
||||||
|
table: "collections");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "logo_source",
|
||||||
|
table: "collections");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "poster_blurhash",
|
||||||
|
table: "collections");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "poster_source",
|
||||||
|
table: "collections");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "thumbnail_blurhash",
|
||||||
|
table: "collections");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "thumbnail_source",
|
||||||
|
table: "collections");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<Dictionary<int, string>>(
|
||||||
|
name: "images",
|
||||||
|
table: "users",
|
||||||
|
type: "jsonb",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<Dictionary<int, string>>(
|
||||||
|
name: "images",
|
||||||
|
table: "shows",
|
||||||
|
type: "jsonb",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<Dictionary<int, string>>(
|
||||||
|
name: "images",
|
||||||
|
table: "seasons",
|
||||||
|
type: "jsonb",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<Dictionary<int, string>>(
|
||||||
|
name: "images",
|
||||||
|
table: "people",
|
||||||
|
type: "jsonb",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<Dictionary<int, string>>(
|
||||||
|
name: "images",
|
||||||
|
table: "episodes",
|
||||||
|
type: "jsonb",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<Dictionary<int, string>>(
|
||||||
|
name: "images",
|
||||||
|
table: "collections",
|
||||||
|
type: "jsonb",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "providers",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
id = table.Column<int>(type: "integer", nullable: false)
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
images = table.Column<Dictionary<int, string>>(type: "jsonb", nullable: true),
|
||||||
|
name = table.Column<string>(type: "text", nullable: true),
|
||||||
|
slug = table.Column<string>(type: "text", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("pk_providers", x => x.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "collection_metadata_id",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
resource_id = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
provider_id = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
data_id = table.Column<string>(type: "text", nullable: true),
|
||||||
|
link = table.Column<string>(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: "episode_metadata_id",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
resource_id = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
provider_id = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
data_id = table.Column<string>(type: "text", nullable: true),
|
||||||
|
link = table.Column<string>(type: "text", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("pk_episode_metadata_id", x => new { x.resource_id, x.provider_id });
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "fk_episode_metadata_id_episodes_episode_id",
|
||||||
|
column: x => x.resource_id,
|
||||||
|
principalTable: "episodes",
|
||||||
|
principalColumn: "id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "fk_episode_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
|
||||||
|
{
|
||||||
|
library_id = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
provider_id = table.Column<int>(type: "integer", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("pk_link_library_provider", x => new { x.library_id, x.provider_id });
|
||||||
|
table.ForeignKey(
|
||||||
|
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_provider_id",
|
||||||
|
column: x => x.provider_id,
|
||||||
|
principalTable: "providers",
|
||||||
|
principalColumn: "id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "people_metadata_id",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
resource_id = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
provider_id = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
data_id = table.Column<string>(type: "text", nullable: true),
|
||||||
|
link = table.Column<string>(type: "text", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("pk_people_metadata_id", x => new { x.resource_id, x.provider_id });
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "fk_people_metadata_id_people_people_id",
|
||||||
|
column: x => x.resource_id,
|
||||||
|
principalTable: "people",
|
||||||
|
principalColumn: "id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "fk_people_metadata_id_providers_provider_id",
|
||||||
|
column: x => x.provider_id,
|
||||||
|
principalTable: "providers",
|
||||||
|
principalColumn: "id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "season_metadata_id",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
resource_id = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
provider_id = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
data_id = table.Column<string>(type: "text", nullable: true),
|
||||||
|
link = table.Column<string>(type: "text", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("pk_season_metadata_id", x => new { x.resource_id, x.provider_id });
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "fk_season_metadata_id_providers_provider_id",
|
||||||
|
column: x => x.provider_id,
|
||||||
|
principalTable: "providers",
|
||||||
|
principalColumn: "id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "fk_season_metadata_id_seasons_season_id",
|
||||||
|
column: x => x.resource_id,
|
||||||
|
principalTable: "seasons",
|
||||||
|
principalColumn: "id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "show_metadata_id",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
resource_id = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
provider_id = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
data_id = table.Column<string>(type: "text", nullable: true),
|
||||||
|
link = table.Column<string>(type: "text", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("pk_show_metadata_id", x => new { x.resource_id, x.provider_id });
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "fk_show_metadata_id_providers_provider_id",
|
||||||
|
column: x => x.provider_id,
|
||||||
|
principalTable: "providers",
|
||||||
|
principalColumn: "id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "fk_show_metadata_id_shows_show_id",
|
||||||
|
column: x => x.resource_id,
|
||||||
|
principalTable: "shows",
|
||||||
|
principalColumn: "id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "studio_metadata_id",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
resource_id = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
provider_id = table.Column<int>(type: "integer", nullable: false),
|
||||||
|
data_id = table.Column<string>(type: "text", nullable: true),
|
||||||
|
link = table.Column<string>(type: "text", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("pk_studio_metadata_id", x => new { x.resource_id, x.provider_id });
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "fk_studio_metadata_id_providers_provider_id",
|
||||||
|
column: x => x.provider_id,
|
||||||
|
principalTable: "providers",
|
||||||
|
principalColumn: "id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "fk_studio_metadata_id_studios_studio_id",
|
||||||
|
column: x => x.resource_id,
|
||||||
|
principalTable: "studios",
|
||||||
|
principalColumn: "id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "ix_collection_metadata_id_provider_id",
|
||||||
|
table: "collection_metadata_id",
|
||||||
|
column: "provider_id");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "ix_episode_metadata_id_provider_id",
|
||||||
|
table: "episode_metadata_id",
|
||||||
|
column: "provider_id");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "ix_link_library_provider_provider_id",
|
||||||
|
table: "link_library_provider",
|
||||||
|
column: "provider_id");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "ix_people_metadata_id_provider_id",
|
||||||
|
table: "people_metadata_id",
|
||||||
|
column: "provider_id");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "ix_providers_slug",
|
||||||
|
table: "providers",
|
||||||
|
column: "slug",
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "ix_season_metadata_id_provider_id",
|
||||||
|
table: "season_metadata_id",
|
||||||
|
column: "provider_id");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "ix_show_metadata_id_provider_id",
|
||||||
|
table: "show_metadata_id",
|
||||||
|
column: "provider_id");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "ix_studio_metadata_id_provider_id",
|
||||||
|
table: "studio_metadata_id",
|
||||||
|
column: "provider_id");
|
||||||
|
|
||||||
|
MigrationHelper.CreateLibraryItemsView(migrationBuilder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
@ -33,11 +33,6 @@ namespace Kyoo.Postgresql
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class PostgresContext : DatabaseContext
|
public class PostgresContext : DatabaseContext
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// The connection string to use.
|
|
||||||
/// </summary>
|
|
||||||
private readonly string _connection;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Is this instance in debug mode?
|
/// Is this instance in debug mode?
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -78,7 +73,6 @@ namespace Kyoo.Postgresql
|
|||||||
/// <param name="debugMode">Is this instance in debug mode?</param>
|
/// <param name="debugMode">Is this instance in debug mode?</param>
|
||||||
public PostgresContext(string connection, bool debugMode)
|
public PostgresContext(string connection, bool debugMode)
|
||||||
{
|
{
|
||||||
_connection = connection;
|
|
||||||
_debugMode = debugMode;
|
_debugMode = debugMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,31 +110,6 @@ namespace Kyoo.Postgresql
|
|||||||
.Property(x => x.ExtraData)
|
.Property(x => x.ExtraData)
|
||||||
.HasColumnType("jsonb");
|
.HasColumnType("jsonb");
|
||||||
|
|
||||||
modelBuilder.Entity<LibraryItem>()
|
|
||||||
.Property(x => x.Images)
|
|
||||||
.HasColumnType("jsonb");
|
|
||||||
modelBuilder.Entity<Collection>()
|
|
||||||
.Property(x => x.Images)
|
|
||||||
.HasColumnType("jsonb");
|
|
||||||
modelBuilder.Entity<Show>()
|
|
||||||
.Property(x => x.Images)
|
|
||||||
.HasColumnType("jsonb");
|
|
||||||
modelBuilder.Entity<Season>()
|
|
||||||
.Property(x => x.Images)
|
|
||||||
.HasColumnType("jsonb");
|
|
||||||
modelBuilder.Entity<Episode>()
|
|
||||||
.Property(x => x.Images)
|
|
||||||
.HasColumnType("jsonb");
|
|
||||||
modelBuilder.Entity<People>()
|
|
||||||
.Property(x => x.Images)
|
|
||||||
.HasColumnType("jsonb");
|
|
||||||
modelBuilder.Entity<Provider>()
|
|
||||||
.Property(x => x.Images)
|
|
||||||
.HasColumnType("jsonb");
|
|
||||||
modelBuilder.Entity<User>()
|
|
||||||
.Property(x => x.Images)
|
|
||||||
.HasColumnType("jsonb");
|
|
||||||
|
|
||||||
base.OnModelCreating(modelBuilder);
|
base.OnModelCreating(modelBuilder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Kyoo.Abstractions.Controllers;
|
using Kyoo.Abstractions.Controllers;
|
||||||
@ -87,7 +86,6 @@ namespace Kyoo.Swagger
|
|||||||
x.IsNullableRaw = false;
|
x.IsNullableRaw = false;
|
||||||
x.Type = JsonObjectType.String | JsonObjectType.Integer;
|
x.Type = JsonObjectType.String | JsonObjectType.Integer;
|
||||||
}));
|
}));
|
||||||
document.SchemaProcessors.Add(new ThumbnailProcessor());
|
|
||||||
|
|
||||||
document.AddSecurity(nameof(Kyoo), new OpenApiSecurityScheme
|
document.AddSecurity(nameof(Kyoo), new OpenApiSecurityScheme
|
||||||
{
|
{
|
||||||
|
@ -1,49 +0,0 @@
|
|||||||
// Kyoo - A portable and vast media library solution.
|
|
||||||
// Copyright (c) Kyoo.
|
|
||||||
//
|
|
||||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
|
||||||
//
|
|
||||||
// Kyoo is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// any later version.
|
|
||||||
//
|
|
||||||
// Kyoo is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
using Kyoo.Abstractions.Models;
|
|
||||||
using NJsonSchema;
|
|
||||||
using NJsonSchema.Generation;
|
|
||||||
|
|
||||||
namespace Kyoo.Swagger
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// An operation processor to add computed fields of <see cref="IThumbnails"/>.
|
|
||||||
/// </summary>
|
|
||||||
public class ThumbnailProcessor : ISchemaProcessor
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
|
||||||
public void Process(SchemaProcessorContext context)
|
|
||||||
{
|
|
||||||
if (!context.ContextualType.OriginalType.IsAssignableTo(typeof(IThumbnails)))
|
|
||||||
return;
|
|
||||||
foreach ((int _, string imageP) in Images.ImageName)
|
|
||||||
{
|
|
||||||
string image = imageP.ToLower()[0] + imageP[1..];
|
|
||||||
context.Schema.Properties.Add(image, new JsonSchemaProperty
|
|
||||||
{
|
|
||||||
Type = JsonObjectType.String,
|
|
||||||
IsNullableRaw = true,
|
|
||||||
Description = $"An url to the {image} of this resource. If this resource does not have an image, " +
|
|
||||||
$"the link will be null. If the kyoo's instance is not capable of handling this kind of image " +
|
|
||||||
$"for the specific resource, this field won't be present."
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -37,22 +37,20 @@ namespace Kyoo.Tests.Database
|
|||||||
{
|
{
|
||||||
Context = new PostgresTestContext(postgres, output);
|
Context = new PostgresTestContext(postgres, output);
|
||||||
|
|
||||||
ProviderRepository provider = new(_NewContext());
|
LibraryRepository library = new(_NewContext());
|
||||||
LibraryRepository library = new(_NewContext(), provider);
|
CollectionRepository collection = new(_NewContext());
|
||||||
CollectionRepository collection = new(_NewContext(), provider);
|
|
||||||
GenreRepository genre = new(_NewContext());
|
GenreRepository genre = new(_NewContext());
|
||||||
StudioRepository studio = new(_NewContext(), provider);
|
StudioRepository studio = new(_NewContext());
|
||||||
PeopleRepository people = new(_NewContext(), provider,
|
PeopleRepository people = new(_NewContext(),
|
||||||
new Lazy<IShowRepository>(() => LibraryManager.ShowRepository));
|
new Lazy<IShowRepository>(() => LibraryManager.ShowRepository));
|
||||||
ShowRepository show = new(_NewContext(), studio, people, genre, provider);
|
ShowRepository show = new(_NewContext(), studio, people, genre);
|
||||||
SeasonRepository season = new(_NewContext(), show, provider);
|
SeasonRepository season = new(_NewContext(), show);
|
||||||
LibraryItemRepository libraryItem = new(_NewContext(),
|
LibraryItemRepository libraryItem = new(_NewContext(),
|
||||||
new Lazy<ILibraryRepository>(() => LibraryManager.LibraryRepository));
|
new Lazy<ILibraryRepository>(() => LibraryManager.LibraryRepository));
|
||||||
EpisodeRepository episode = new(_NewContext(), show, provider);
|
EpisodeRepository episode = new(_NewContext(), show);
|
||||||
UserRepository user = new(_NewContext());
|
UserRepository user = new(_NewContext());
|
||||||
|
|
||||||
LibraryManager = new LibraryManager(new IBaseRepository[] {
|
LibraryManager = new LibraryManager(new IBaseRepository[] {
|
||||||
provider,
|
|
||||||
library,
|
library,
|
||||||
libraryItem,
|
libraryItem,
|
||||||
collection,
|
collection,
|
||||||
|
@ -78,7 +78,7 @@ namespace Kyoo.Tests.Database
|
|||||||
public async Task CreateWithExternalIdTest()
|
public async Task CreateWithExternalIdTest()
|
||||||
{
|
{
|
||||||
Collection collection = TestSample.GetNew<Collection>();
|
Collection collection = TestSample.GetNew<Collection>();
|
||||||
collection.ExternalIDs = new[]
|
collection.ExternalId = new[]
|
||||||
{
|
{
|
||||||
new MetadataID
|
new MetadataID
|
||||||
{
|
{
|
||||||
@ -96,10 +96,10 @@ namespace Kyoo.Tests.Database
|
|||||||
await _repository.Create(collection);
|
await _repository.Create(collection);
|
||||||
|
|
||||||
Collection retrieved = await _repository.Get(2);
|
Collection retrieved = await _repository.Get(2);
|
||||||
await Repositories.LibraryManager.Load(retrieved, x => x.ExternalIDs);
|
await Repositories.LibraryManager.Load(retrieved, x => x.ExternalId);
|
||||||
Assert.Equal(2, retrieved.ExternalIDs.Count);
|
Assert.Equal(2, retrieved.ExternalId.Count);
|
||||||
KAssert.DeepEqual(collection.ExternalIDs.First(), retrieved.ExternalIDs.First());
|
KAssert.DeepEqual(collection.ExternalId.First(), retrieved.ExternalId.First());
|
||||||
KAssert.DeepEqual(collection.ExternalIDs.Last(), retrieved.ExternalIDs.Last());
|
KAssert.DeepEqual(collection.ExternalId.Last(), retrieved.ExternalId.Last());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@ -123,7 +123,7 @@ namespace Kyoo.Tests.Database
|
|||||||
public async Task EditMetadataTest()
|
public async Task EditMetadataTest()
|
||||||
{
|
{
|
||||||
Collection value = await _repository.Get(TestSample.Get<Collection>().Slug);
|
Collection value = await _repository.Get(TestSample.Get<Collection>().Slug);
|
||||||
value.ExternalIDs = new[]
|
value.ExternalId = new[]
|
||||||
{
|
{
|
||||||
new MetadataID
|
new MetadataID
|
||||||
{
|
{
|
||||||
@ -136,7 +136,7 @@ namespace Kyoo.Tests.Database
|
|||||||
|
|
||||||
await using DatabaseContext database = Repositories.Context.New();
|
await using DatabaseContext database = Repositories.Context.New();
|
||||||
Collection retrieved = await database.Collections
|
Collection retrieved = await database.Collections
|
||||||
.Include(x => x.ExternalIDs)
|
.Include(x => x.ExternalId)
|
||||||
.ThenInclude(x => x.Provider)
|
.ThenInclude(x => x.Provider)
|
||||||
.FirstAsync();
|
.FirstAsync();
|
||||||
|
|
||||||
@ -147,7 +147,7 @@ namespace Kyoo.Tests.Database
|
|||||||
public async Task AddMetadataTest()
|
public async Task AddMetadataTest()
|
||||||
{
|
{
|
||||||
Collection value = await _repository.Get(TestSample.Get<Collection>().Slug);
|
Collection value = await _repository.Get(TestSample.Get<Collection>().Slug);
|
||||||
value.ExternalIDs = new List<MetadataID>
|
value.ExternalId = new List<MetadataID>
|
||||||
{
|
{
|
||||||
new()
|
new()
|
||||||
{
|
{
|
||||||
@ -161,14 +161,14 @@ namespace Kyoo.Tests.Database
|
|||||||
{
|
{
|
||||||
await using DatabaseContext database = Repositories.Context.New();
|
await using DatabaseContext database = Repositories.Context.New();
|
||||||
Collection retrieved = await database.Collections
|
Collection retrieved = await database.Collections
|
||||||
.Include(x => x.ExternalIDs)
|
.Include(x => x.ExternalId)
|
||||||
.ThenInclude(x => x.Provider)
|
.ThenInclude(x => x.Provider)
|
||||||
.FirstAsync();
|
.FirstAsync();
|
||||||
|
|
||||||
KAssert.DeepEqual(value, retrieved);
|
KAssert.DeepEqual(value, retrieved);
|
||||||
}
|
}
|
||||||
|
|
||||||
value.ExternalIDs.Add(new MetadataID
|
value.ExternalId.Add(new MetadataID
|
||||||
{
|
{
|
||||||
Provider = TestSample.GetNew<Provider>(),
|
Provider = TestSample.GetNew<Provider>(),
|
||||||
Link = "link",
|
Link = "link",
|
||||||
@ -179,7 +179,7 @@ namespace Kyoo.Tests.Database
|
|||||||
{
|
{
|
||||||
await using DatabaseContext database = Repositories.Context.New();
|
await using DatabaseContext database = Repositories.Context.New();
|
||||||
Collection retrieved = await database.Collections
|
Collection retrieved = await database.Collections
|
||||||
.Include(x => x.ExternalIDs)
|
.Include(x => x.ExternalId)
|
||||||
.ThenInclude(x => x.Provider)
|
.ThenInclude(x => x.Provider)
|
||||||
.FirstAsync();
|
.FirstAsync();
|
||||||
|
|
||||||
|
@ -206,7 +206,7 @@ namespace Kyoo.Tests.Database
|
|||||||
public async Task CreateWithExternalIdTest()
|
public async Task CreateWithExternalIdTest()
|
||||||
{
|
{
|
||||||
Episode value = TestSample.GetNew<Episode>();
|
Episode value = TestSample.GetNew<Episode>();
|
||||||
value.ExternalIDs = new[]
|
value.ExternalId = new[]
|
||||||
{
|
{
|
||||||
new MetadataID
|
new MetadataID
|
||||||
{
|
{
|
||||||
@ -224,10 +224,10 @@ namespace Kyoo.Tests.Database
|
|||||||
await _repository.Create(value);
|
await _repository.Create(value);
|
||||||
|
|
||||||
Episode retrieved = await _repository.Get(2);
|
Episode retrieved = await _repository.Get(2);
|
||||||
await Repositories.LibraryManager.Load(retrieved, x => x.ExternalIDs);
|
await Repositories.LibraryManager.Load(retrieved, x => x.ExternalId);
|
||||||
Assert.Equal(2, retrieved.ExternalIDs.Count);
|
Assert.Equal(2, retrieved.ExternalId.Count);
|
||||||
KAssert.DeepEqual(value.ExternalIDs.First(), retrieved.ExternalIDs.First());
|
KAssert.DeepEqual(value.ExternalId.First(), retrieved.ExternalId.First());
|
||||||
KAssert.DeepEqual(value.ExternalIDs.Last(), retrieved.ExternalIDs.Last());
|
KAssert.DeepEqual(value.ExternalId.Last(), retrieved.ExternalId.Last());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@ -251,7 +251,7 @@ namespace Kyoo.Tests.Database
|
|||||||
public async Task EditMetadataTest()
|
public async Task EditMetadataTest()
|
||||||
{
|
{
|
||||||
Episode value = await _repository.Get(TestSample.Get<Episode>().Slug);
|
Episode value = await _repository.Get(TestSample.Get<Episode>().Slug);
|
||||||
value.ExternalIDs = new[]
|
value.ExternalId = new[]
|
||||||
{
|
{
|
||||||
new MetadataID
|
new MetadataID
|
||||||
{
|
{
|
||||||
@ -264,7 +264,7 @@ namespace Kyoo.Tests.Database
|
|||||||
|
|
||||||
await using DatabaseContext database = Repositories.Context.New();
|
await using DatabaseContext database = Repositories.Context.New();
|
||||||
Episode retrieved = await database.Episodes
|
Episode retrieved = await database.Episodes
|
||||||
.Include(x => x.ExternalIDs)
|
.Include(x => x.ExternalId)
|
||||||
.ThenInclude(x => x.Provider)
|
.ThenInclude(x => x.Provider)
|
||||||
.FirstAsync();
|
.FirstAsync();
|
||||||
|
|
||||||
@ -275,7 +275,7 @@ namespace Kyoo.Tests.Database
|
|||||||
public async Task AddMetadataTest()
|
public async Task AddMetadataTest()
|
||||||
{
|
{
|
||||||
Episode value = await _repository.Get(TestSample.Get<Episode>().Slug);
|
Episode value = await _repository.Get(TestSample.Get<Episode>().Slug);
|
||||||
value.ExternalIDs = new List<MetadataID>
|
value.ExternalId = new List<MetadataID>
|
||||||
{
|
{
|
||||||
new()
|
new()
|
||||||
{
|
{
|
||||||
@ -289,14 +289,14 @@ namespace Kyoo.Tests.Database
|
|||||||
{
|
{
|
||||||
await using DatabaseContext database = Repositories.Context.New();
|
await using DatabaseContext database = Repositories.Context.New();
|
||||||
Episode retrieved = await database.Episodes
|
Episode retrieved = await database.Episodes
|
||||||
.Include(x => x.ExternalIDs)
|
.Include(x => x.ExternalId)
|
||||||
.ThenInclude(x => x.Provider)
|
.ThenInclude(x => x.Provider)
|
||||||
.FirstAsync();
|
.FirstAsync();
|
||||||
|
|
||||||
KAssert.DeepEqual(value, retrieved);
|
KAssert.DeepEqual(value, retrieved);
|
||||||
}
|
}
|
||||||
|
|
||||||
value.ExternalIDs.Add(new MetadataID
|
value.ExternalId.Add(new MetadataID
|
||||||
{
|
{
|
||||||
Provider = TestSample.GetNew<Provider>(),
|
Provider = TestSample.GetNew<Provider>(),
|
||||||
Link = "link",
|
Link = "link",
|
||||||
@ -307,7 +307,7 @@ namespace Kyoo.Tests.Database
|
|||||||
{
|
{
|
||||||
await using DatabaseContext database = Repositories.Context.New();
|
await using DatabaseContext database = Repositories.Context.New();
|
||||||
Episode retrieved = await database.Episodes
|
Episode retrieved = await database.Episodes
|
||||||
.Include(x => x.ExternalIDs)
|
.Include(x => x.ExternalId)
|
||||||
.ThenInclude(x => x.Provider)
|
.ThenInclude(x => x.Provider)
|
||||||
.FirstAsync();
|
.FirstAsync();
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ namespace Kyoo.Tests.Database
|
|||||||
public async Task CreateWithExternalIdTest()
|
public async Task CreateWithExternalIdTest()
|
||||||
{
|
{
|
||||||
People value = TestSample.GetNew<People>();
|
People value = TestSample.GetNew<People>();
|
||||||
value.ExternalIDs = new[]
|
value.ExternalId = new[]
|
||||||
{
|
{
|
||||||
new MetadataID
|
new MetadataID
|
||||||
{
|
{
|
||||||
@ -70,10 +70,10 @@ namespace Kyoo.Tests.Database
|
|||||||
await _repository.Create(value);
|
await _repository.Create(value);
|
||||||
|
|
||||||
People retrieved = await _repository.Get(2);
|
People retrieved = await _repository.Get(2);
|
||||||
await Repositories.LibraryManager.Load(retrieved, x => x.ExternalIDs);
|
await Repositories.LibraryManager.Load(retrieved, x => x.ExternalId);
|
||||||
Assert.Equal(2, retrieved.ExternalIDs.Count);
|
Assert.Equal(2, retrieved.ExternalId.Count);
|
||||||
KAssert.DeepEqual(value.ExternalIDs.First(), retrieved.ExternalIDs.First());
|
KAssert.DeepEqual(value.ExternalId.First(), retrieved.ExternalId.First());
|
||||||
KAssert.DeepEqual(value.ExternalIDs.Last(), retrieved.ExternalIDs.Last());
|
KAssert.DeepEqual(value.ExternalId.Last(), retrieved.ExternalId.Last());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@ -97,7 +97,7 @@ namespace Kyoo.Tests.Database
|
|||||||
public async Task EditMetadataTest()
|
public async Task EditMetadataTest()
|
||||||
{
|
{
|
||||||
People value = await _repository.Get(TestSample.Get<People>().Slug);
|
People value = await _repository.Get(TestSample.Get<People>().Slug);
|
||||||
value.ExternalIDs = new[]
|
value.ExternalId = new[]
|
||||||
{
|
{
|
||||||
new MetadataID
|
new MetadataID
|
||||||
{
|
{
|
||||||
@ -110,7 +110,7 @@ namespace Kyoo.Tests.Database
|
|||||||
|
|
||||||
await using DatabaseContext database = Repositories.Context.New();
|
await using DatabaseContext database = Repositories.Context.New();
|
||||||
People retrieved = await database.People
|
People retrieved = await database.People
|
||||||
.Include(x => x.ExternalIDs)
|
.Include(x => x.ExternalId)
|
||||||
.ThenInclude(x => x.Provider)
|
.ThenInclude(x => x.Provider)
|
||||||
.FirstAsync();
|
.FirstAsync();
|
||||||
|
|
||||||
@ -121,7 +121,7 @@ namespace Kyoo.Tests.Database
|
|||||||
public async Task AddMetadataTest()
|
public async Task AddMetadataTest()
|
||||||
{
|
{
|
||||||
People value = await _repository.Get(TestSample.Get<People>().Slug);
|
People value = await _repository.Get(TestSample.Get<People>().Slug);
|
||||||
value.ExternalIDs = new List<MetadataID>
|
value.ExternalId = new List<MetadataID>
|
||||||
{
|
{
|
||||||
new()
|
new()
|
||||||
{
|
{
|
||||||
@ -135,14 +135,14 @@ namespace Kyoo.Tests.Database
|
|||||||
{
|
{
|
||||||
await using DatabaseContext database = Repositories.Context.New();
|
await using DatabaseContext database = Repositories.Context.New();
|
||||||
People retrieved = await database.People
|
People retrieved = await database.People
|
||||||
.Include(x => x.ExternalIDs)
|
.Include(x => x.ExternalId)
|
||||||
.ThenInclude(x => x.Provider)
|
.ThenInclude(x => x.Provider)
|
||||||
.FirstAsync();
|
.FirstAsync();
|
||||||
|
|
||||||
KAssert.DeepEqual(value, retrieved);
|
KAssert.DeepEqual(value, retrieved);
|
||||||
}
|
}
|
||||||
|
|
||||||
value.ExternalIDs.Add(new MetadataID
|
value.ExternalId.Add(new MetadataID
|
||||||
{
|
{
|
||||||
Provider = TestSample.GetNew<Provider>(),
|
Provider = TestSample.GetNew<Provider>(),
|
||||||
Link = "link",
|
Link = "link",
|
||||||
@ -153,7 +153,7 @@ namespace Kyoo.Tests.Database
|
|||||||
{
|
{
|
||||||
await using DatabaseContext database = Repositories.Context.New();
|
await using DatabaseContext database = Repositories.Context.New();
|
||||||
People retrieved = await database.People
|
People retrieved = await database.People
|
||||||
.Include(x => x.ExternalIDs)
|
.Include(x => x.ExternalId)
|
||||||
.ThenInclude(x => x.Provider)
|
.ThenInclude(x => x.Provider)
|
||||||
.FirstAsync();
|
.FirstAsync();
|
||||||
|
|
||||||
|
@ -93,7 +93,7 @@ namespace Kyoo.Tests.Database
|
|||||||
public async Task CreateWithExternalIdTest()
|
public async Task CreateWithExternalIdTest()
|
||||||
{
|
{
|
||||||
Season season = TestSample.GetNew<Season>();
|
Season season = TestSample.GetNew<Season>();
|
||||||
season.ExternalIDs = new[]
|
season.ExternalId = new[]
|
||||||
{
|
{
|
||||||
new MetadataID
|
new MetadataID
|
||||||
{
|
{
|
||||||
@ -111,10 +111,10 @@ namespace Kyoo.Tests.Database
|
|||||||
await _repository.Create(season);
|
await _repository.Create(season);
|
||||||
|
|
||||||
Season retrieved = await _repository.Get(2);
|
Season retrieved = await _repository.Get(2);
|
||||||
await Repositories.LibraryManager.Load(retrieved, x => x.ExternalIDs);
|
await Repositories.LibraryManager.Load(retrieved, x => x.ExternalId);
|
||||||
Assert.Equal(2, retrieved.ExternalIDs.Count);
|
Assert.Equal(2, retrieved.ExternalId.Count);
|
||||||
KAssert.DeepEqual(season.ExternalIDs.First(), retrieved.ExternalIDs.First());
|
KAssert.DeepEqual(season.ExternalId.First(), retrieved.ExternalId.First());
|
||||||
KAssert.DeepEqual(season.ExternalIDs.Last(), retrieved.ExternalIDs.Last());
|
KAssert.DeepEqual(season.ExternalId.Last(), retrieved.ExternalId.Last());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@ -138,7 +138,7 @@ namespace Kyoo.Tests.Database
|
|||||||
public async Task EditMetadataTest()
|
public async Task EditMetadataTest()
|
||||||
{
|
{
|
||||||
Season value = await _repository.Get(TestSample.Get<Season>().Slug);
|
Season value = await _repository.Get(TestSample.Get<Season>().Slug);
|
||||||
value.ExternalIDs = new[]
|
value.ExternalId = new[]
|
||||||
{
|
{
|
||||||
new MetadataID
|
new MetadataID
|
||||||
{
|
{
|
||||||
@ -151,7 +151,7 @@ namespace Kyoo.Tests.Database
|
|||||||
|
|
||||||
await using DatabaseContext database = Repositories.Context.New();
|
await using DatabaseContext database = Repositories.Context.New();
|
||||||
Season retrieved = await database.Seasons
|
Season retrieved = await database.Seasons
|
||||||
.Include(x => x.ExternalIDs)
|
.Include(x => x.ExternalId)
|
||||||
.ThenInclude(x => x.Provider)
|
.ThenInclude(x => x.Provider)
|
||||||
.FirstAsync();
|
.FirstAsync();
|
||||||
|
|
||||||
@ -162,7 +162,7 @@ namespace Kyoo.Tests.Database
|
|||||||
public async Task AddMetadataTest()
|
public async Task AddMetadataTest()
|
||||||
{
|
{
|
||||||
Season value = await _repository.Get(TestSample.Get<Season>().Slug);
|
Season value = await _repository.Get(TestSample.Get<Season>().Slug);
|
||||||
value.ExternalIDs = new List<MetadataID>
|
value.ExternalId = new List<MetadataID>
|
||||||
{
|
{
|
||||||
new()
|
new()
|
||||||
{
|
{
|
||||||
@ -176,14 +176,14 @@ namespace Kyoo.Tests.Database
|
|||||||
{
|
{
|
||||||
await using DatabaseContext database = Repositories.Context.New();
|
await using DatabaseContext database = Repositories.Context.New();
|
||||||
Season retrieved = await database.Seasons
|
Season retrieved = await database.Seasons
|
||||||
.Include(x => x.ExternalIDs)
|
.Include(x => x.ExternalId)
|
||||||
.ThenInclude(x => x.Provider)
|
.ThenInclude(x => x.Provider)
|
||||||
.FirstAsync();
|
.FirstAsync();
|
||||||
|
|
||||||
KAssert.DeepEqual(value, retrieved);
|
KAssert.DeepEqual(value, retrieved);
|
||||||
}
|
}
|
||||||
|
|
||||||
value.ExternalIDs.Add(new MetadataID
|
value.ExternalId.Add(new MetadataID
|
||||||
{
|
{
|
||||||
Provider = TestSample.GetNew<Provider>(),
|
Provider = TestSample.GetNew<Provider>(),
|
||||||
Link = "link",
|
Link = "link",
|
||||||
@ -194,7 +194,7 @@ namespace Kyoo.Tests.Database
|
|||||||
{
|
{
|
||||||
await using DatabaseContext database = Repositories.Context.New();
|
await using DatabaseContext database = Repositories.Context.New();
|
||||||
Season retrieved = await database.Seasons
|
Season retrieved = await database.Seasons
|
||||||
.Include(x => x.ExternalIDs)
|
.Include(x => x.ExternalId)
|
||||||
.ThenInclude(x => x.Provider)
|
.ThenInclude(x => x.Provider)
|
||||||
.FirstAsync();
|
.FirstAsync();
|
||||||
|
|
||||||
|
@ -180,7 +180,7 @@ namespace Kyoo.Tests.Database
|
|||||||
public async Task EditExternalIDsTest()
|
public async Task EditExternalIDsTest()
|
||||||
{
|
{
|
||||||
Show value = await _repository.Get(TestSample.Get<Show>().Slug);
|
Show value = await _repository.Get(TestSample.Get<Show>().Slug);
|
||||||
value.ExternalIDs = new[]
|
value.ExternalId = new[]
|
||||||
{
|
{
|
||||||
new MetadataID
|
new MetadataID
|
||||||
{
|
{
|
||||||
@ -192,19 +192,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.Provider.Slug }),
|
value.ExternalId.Select(x => new { x.DataID, x.Provider.Slug }),
|
||||||
edited.ExternalIDs.Select(x => new { x.DataID, x.Provider.Slug }));
|
edited.ExternalId.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.ExternalId)
|
||||||
.ThenInclude(x => x.Provider)
|
.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.Provider.Slug }),
|
value.ExternalId.Select(x => new { x.DataID, x.Provider.Slug }),
|
||||||
show.ExternalIDs.Select(x => new { x.DataID, x.Provider.Slug }));
|
show.ExternalId.Select(x => new { x.DataID, x.Provider.Slug }));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@ -225,7 +225,7 @@ namespace Kyoo.Tests.Database
|
|||||||
Assert.Equal("reset", edited.Slug);
|
Assert.Equal("reset", edited.Slug);
|
||||||
Assert.Equal("Reset", edited.Title);
|
Assert.Equal("Reset", edited.Title);
|
||||||
Assert.Null(edited.Aliases);
|
Assert.Null(edited.Aliases);
|
||||||
Assert.Null(edited.ExternalIDs);
|
Assert.Null(edited.ExternalId);
|
||||||
Assert.Null(edited.People);
|
Assert.Null(edited.People);
|
||||||
Assert.Null(edited.Genres);
|
Assert.Null(edited.Genres);
|
||||||
Assert.Null(edited.Studio);
|
Assert.Null(edited.Studio);
|
||||||
@ -237,7 +237,7 @@ namespace Kyoo.Tests.Database
|
|||||||
Show expected = TestSample.Get<Show>();
|
Show expected = TestSample.Get<Show>();
|
||||||
expected.ID = 0;
|
expected.ID = 0;
|
||||||
expected.Slug = "created-relation-test";
|
expected.Slug = "created-relation-test";
|
||||||
expected.ExternalIDs = new[]
|
expected.ExternalId = new[]
|
||||||
{
|
{
|
||||||
new MetadataID
|
new MetadataID
|
||||||
{
|
{
|
||||||
@ -269,7 +269,7 @@ namespace Kyoo.Tests.Database
|
|||||||
|
|
||||||
await using DatabaseContext context = Repositories.Context.New();
|
await using DatabaseContext context = Repositories.Context.New();
|
||||||
Show retrieved = await context.Shows
|
Show retrieved = await context.Shows
|
||||||
.Include(x => x.ExternalIDs)
|
.Include(x => x.ExternalId)
|
||||||
.ThenInclude(x => x.Provider)
|
.ThenInclude(x => x.Provider)
|
||||||
.Include(x => x.Genres)
|
.Include(x => x.Genres)
|
||||||
.Include(x => x.People)
|
.Include(x => x.People)
|
||||||
@ -300,7 +300,7 @@ namespace Kyoo.Tests.Database
|
|||||||
Show expected = TestSample.Get<Show>();
|
Show expected = TestSample.Get<Show>();
|
||||||
expected.ID = 0;
|
expected.ID = 0;
|
||||||
expected.Slug = "created-relation-test";
|
expected.Slug = "created-relation-test";
|
||||||
expected.ExternalIDs = new[]
|
expected.ExternalId = new[]
|
||||||
{
|
{
|
||||||
new MetadataID
|
new MetadataID
|
||||||
{
|
{
|
||||||
@ -312,12 +312,12 @@ namespace Kyoo.Tests.Database
|
|||||||
KAssert.DeepEqual(expected, created);
|
KAssert.DeepEqual(expected, created);
|
||||||
await using DatabaseContext context = Repositories.Context.New();
|
await using DatabaseContext context = Repositories.Context.New();
|
||||||
Show retrieved = await context.Shows
|
Show retrieved = await context.Shows
|
||||||
.Include(x => x.ExternalIDs)
|
.Include(x => x.ExternalId)
|
||||||
.ThenInclude(x => x.Provider)
|
.ThenInclude(x => x.Provider)
|
||||||
.FirstAsync(x => x.ID == created.ID);
|
.FirstAsync(x => x.ID == created.ID);
|
||||||
KAssert.DeepEqual(expected, retrieved);
|
KAssert.DeepEqual(expected, retrieved);
|
||||||
Assert.Single(retrieved.ExternalIDs);
|
Assert.Single(retrieved.ExternalId);
|
||||||
Assert.Equal("ID", retrieved.ExternalIDs.First().DataID);
|
Assert.Equal("ID", retrieved.ExternalId.First().DataID);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
@ -350,14 +350,9 @@ namespace Kyoo.Tests
|
|||||||
people.ID = 0;
|
people.ID = 0;
|
||||||
context.People.Add(people);
|
context.People.Add(people);
|
||||||
|
|
||||||
Provider provider = Get<Provider>();
|
|
||||||
provider.ID = 0;
|
|
||||||
context.Providers.Add(provider);
|
|
||||||
|
|
||||||
Library library = Get<Library>();
|
Library library = Get<Library>();
|
||||||
library.ID = 0;
|
library.ID = 0;
|
||||||
library.Collections = new List<Collection> { collection };
|
library.Collections = new List<Collection> { collection };
|
||||||
library.Providers = new List<Provider> { provider };
|
|
||||||
context.Libraries.Add(library);
|
context.Libraries.Add(library);
|
||||||
|
|
||||||
User user = Get<User>();
|
User user = Get<User>();
|
||||||
|
@ -353,69 +353,54 @@ namespace Kyoo.Tests.Utility
|
|||||||
{
|
{
|
||||||
ID = 5,
|
ID = 5,
|
||||||
Name = "merged",
|
Name = "merged",
|
||||||
Images = new Dictionary<int, string>
|
|
||||||
{
|
|
||||||
[Images.Logo] = "logo",
|
|
||||||
[Images.Poster] = "poster"
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
Collection collection2 = new()
|
Collection collection2 = new()
|
||||||
{
|
{
|
||||||
Name = "test",
|
Name = "test",
|
||||||
Images = new Dictionary<int, string>
|
|
||||||
{
|
|
||||||
[Images.Poster] = "new-poster",
|
|
||||||
[Images.Thumbnail] = "thumbnails"
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
Collection ret = Merger.Complete(collection, collection2);
|
Collection ret = Merger.Complete(collection, collection2);
|
||||||
Assert.True(ReferenceEquals(collection, ret));
|
Assert.True(ReferenceEquals(collection, ret));
|
||||||
Assert.Equal(5, ret.ID);
|
Assert.Equal(5, ret.ID);
|
||||||
Assert.Equal("test", ret.Name);
|
Assert.Equal("test", ret.Name);
|
||||||
Assert.Null(ret.Slug);
|
Assert.Null(ret.Slug);
|
||||||
Assert.Equal(3, ret.Images.Count);
|
|
||||||
Assert.Equal("new-poster", ret.Images[Images.Poster]);
|
|
||||||
Assert.Equal("thumbnails", ret.Images[Images.Thumbnail]);
|
|
||||||
Assert.Equal("logo", ret.Images[Images.Logo]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void CompleteDictionaryOutParam()
|
public void CompleteDictionaryOutParam()
|
||||||
{
|
{
|
||||||
Dictionary<int, string> first = new()
|
Dictionary<string, string> first = new()
|
||||||
{
|
{
|
||||||
[Images.Logo] = "logo",
|
["logo"] = "logo",
|
||||||
[Images.Poster] = "poster"
|
["poster"] = "poster"
|
||||||
};
|
};
|
||||||
Dictionary<int, string> second = new()
|
Dictionary<string, string> second = new()
|
||||||
{
|
{
|
||||||
[Images.Poster] = "new-poster",
|
["poster"] = "new-poster",
|
||||||
[Images.Thumbnail] = "thumbnails"
|
["thumbnail"] = "thumbnails"
|
||||||
};
|
};
|
||||||
IDictionary<int, string> ret = Merger.CompleteDictionaries(first, second, out bool changed);
|
IDictionary<string, string> ret = Merger.CompleteDictionaries(first, second, out bool changed);
|
||||||
Assert.True(changed);
|
Assert.True(changed);
|
||||||
Assert.Equal(3, ret.Count);
|
Assert.Equal(3, ret.Count);
|
||||||
Assert.Equal("new-poster", ret[Images.Poster]);
|
Assert.Equal("new-poster", ret["poster"]);
|
||||||
Assert.Equal("thumbnails", ret[Images.Thumbnail]);
|
Assert.Equal("thumbnails", ret["thumbnail"]);
|
||||||
Assert.Equal("logo", ret[Images.Logo]);
|
Assert.Equal("logo", ret["logo"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void CompleteDictionaryEqualTest()
|
public void CompleteDictionaryEqualTest()
|
||||||
{
|
{
|
||||||
Dictionary<int, string> first = new()
|
Dictionary<string, string> first = new()
|
||||||
{
|
{
|
||||||
[Images.Poster] = "poster"
|
["poster"] = "poster"
|
||||||
};
|
};
|
||||||
Dictionary<int, string> second = new()
|
Dictionary<string, string> second = new()
|
||||||
{
|
{
|
||||||
[Images.Poster] = "new-poster",
|
["poster"] = "new-poster",
|
||||||
};
|
};
|
||||||
IDictionary<int, string> ret = Merger.CompleteDictionaries(first, second, out bool changed);
|
IDictionary<string, string> ret = Merger.CompleteDictionaries(first, second, out bool changed);
|
||||||
Assert.True(changed);
|
Assert.True(changed);
|
||||||
Assert.Single(ret);
|
Assert.Single(ret);
|
||||||
Assert.Equal("new-poster", ret[Images.Poster]);
|
Assert.Equal("new-poster", ret["poster"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TestMergeSetter
|
private class TestMergeSetter
|
||||||
@ -473,81 +458,81 @@ namespace Kyoo.Tests.Utility
|
|||||||
[Fact]
|
[Fact]
|
||||||
public void MergeDictionaryNullValue()
|
public void MergeDictionaryNullValue()
|
||||||
{
|
{
|
||||||
Dictionary<int, string> first = new()
|
Dictionary<string, string> first = new()
|
||||||
{
|
{
|
||||||
[Images.Logo] = "logo",
|
["logo"] = "logo",
|
||||||
[Images.Poster] = null
|
["poster"] = null
|
||||||
};
|
};
|
||||||
Dictionary<int, string> second = new()
|
Dictionary<string, string> second = new()
|
||||||
{
|
{
|
||||||
[Images.Poster] = "new-poster",
|
["poster"] = "new-poster",
|
||||||
[Images.Thumbnail] = "thumbnails"
|
["thumbnail"] = "thumbnails"
|
||||||
};
|
};
|
||||||
IDictionary<int, string> ret = Merger.MergeDictionaries(first, second, out bool changed);
|
IDictionary<string, string> ret = Merger.MergeDictionaries(first, second, out bool changed);
|
||||||
Assert.True(changed);
|
Assert.True(changed);
|
||||||
Assert.Equal(3, ret.Count);
|
Assert.Equal(3, ret.Count);
|
||||||
Assert.Equal("new-poster", ret[Images.Poster]);
|
Assert.Equal("new-poster", ret["poster"]);
|
||||||
Assert.Equal("thumbnails", ret[Images.Thumbnail]);
|
Assert.Equal("thumbnails", ret["thumbnail"]);
|
||||||
Assert.Equal("logo", ret[Images.Logo]);
|
Assert.Equal("logo", ret["logo"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void MergeDictionaryNullValueNoChange()
|
public void MergeDictionaryNullValueNoChange()
|
||||||
{
|
{
|
||||||
Dictionary<int, string> first = new()
|
Dictionary<string, string> first = new()
|
||||||
{
|
{
|
||||||
[Images.Logo] = "logo",
|
["logo"] = "logo",
|
||||||
[Images.Poster] = null
|
["poster"] = null
|
||||||
};
|
};
|
||||||
Dictionary<int, string> second = new()
|
Dictionary<string, string> second = new()
|
||||||
{
|
{
|
||||||
[Images.Poster] = null,
|
["poster"] = null,
|
||||||
};
|
};
|
||||||
IDictionary<int, string> ret = Merger.MergeDictionaries(first, second, out bool changed);
|
IDictionary<string, string> ret = Merger.MergeDictionaries(first, second, out bool changed);
|
||||||
Assert.False(changed);
|
Assert.False(changed);
|
||||||
Assert.Equal(2, ret.Count);
|
Assert.Equal(2, ret.Count);
|
||||||
Assert.Null(ret[Images.Poster]);
|
Assert.Null(ret["poster"]);
|
||||||
Assert.Equal("logo", ret[Images.Logo]);
|
Assert.Equal("logo", ret["logo"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void CompleteDictionaryNullValue()
|
public void CompleteDictionaryNullValue()
|
||||||
{
|
{
|
||||||
Dictionary<int, string> first = new()
|
Dictionary<string, string> first = new()
|
||||||
{
|
{
|
||||||
[Images.Logo] = "logo",
|
["logo"] = "logo",
|
||||||
[Images.Poster] = null
|
["poster"] = null
|
||||||
};
|
};
|
||||||
Dictionary<int, string> second = new()
|
Dictionary<string, string> second = new()
|
||||||
{
|
{
|
||||||
[Images.Poster] = "new-poster",
|
["poster"] = "new-poster",
|
||||||
[Images.Thumbnail] = "thumbnails"
|
["thumbnail"] = "thumbnails"
|
||||||
};
|
};
|
||||||
IDictionary<int, string> ret = Merger.CompleteDictionaries(first, second, out bool changed);
|
IDictionary<string, string> ret = Merger.CompleteDictionaries(first, second, out bool changed);
|
||||||
Assert.True(changed);
|
Assert.True(changed);
|
||||||
Assert.Equal(3, ret.Count);
|
Assert.Equal(3, ret.Count);
|
||||||
Assert.Equal("new-poster", ret[Images.Poster]);
|
Assert.Equal("new-poster", ret["poster"]);
|
||||||
Assert.Equal("thumbnails", ret[Images.Thumbnail]);
|
Assert.Equal("thumbnails", ret["thumbnail"]);
|
||||||
Assert.Equal("logo", ret[Images.Logo]);
|
Assert.Equal("logo", ret["logo"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void CompleteDictionaryNullValueNoChange()
|
public void CompleteDictionaryNullValueNoChange()
|
||||||
{
|
{
|
||||||
Dictionary<int, string> first = new()
|
Dictionary<string, string> first = new()
|
||||||
{
|
{
|
||||||
[Images.Logo] = "logo",
|
["logo"] = "logo",
|
||||||
[Images.Poster] = null
|
["poster"] = null
|
||||||
};
|
};
|
||||||
Dictionary<int, string> second = new()
|
Dictionary<string, string> second = new()
|
||||||
{
|
{
|
||||||
[Images.Poster] = null,
|
["poster"] = null,
|
||||||
};
|
};
|
||||||
IDictionary<int, string> ret = Merger.CompleteDictionaries(first, second, out bool changed);
|
IDictionary<string, string> ret = Merger.CompleteDictionaries(first, second, out bool changed);
|
||||||
Assert.False(changed);
|
Assert.False(changed);
|
||||||
Assert.Equal(2, ret.Count);
|
Assert.Equal(2, ret.Count);
|
||||||
Assert.Null(ret[Images.Poster]);
|
Assert.Null(ret["poster"]);
|
||||||
Assert.Equal("logo", ret[Images.Logo]);
|
Assert.Equal("logo", ret["logo"]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ namespace Kyoo.Tests.Utility
|
|||||||
Assert.True(KUtility.IsPropertyExpression(member));
|
Assert.True(KUtility.IsPropertyExpression(member));
|
||||||
Assert.True(KUtility.IsPropertyExpression(memberCast));
|
Assert.True(KUtility.IsPropertyExpression(memberCast));
|
||||||
|
|
||||||
Expression<Func<Show, object>> call = x => x.GetID("test");
|
Expression<Func<Show, object>> call = x => x.ToString();
|
||||||
Assert.False(KUtility.IsPropertyExpression(call));
|
Assert.False(KUtility.IsPropertyExpression(call));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,7 +102,7 @@ const Menu = <AsProps,>({
|
|||||||
}),
|
}),
|
||||||
])}
|
])}
|
||||||
>
|
>
|
||||||
<ScrollView {...css([])}>
|
<ScrollView>
|
||||||
<IconButton
|
<IconButton
|
||||||
icon={Close}
|
icon={Close}
|
||||||
color={theme.colors.black}
|
color={theme.colors.black}
|
||||||
|
@ -44,7 +44,5 @@ class Episode:
|
|||||||
"images": {
|
"images": {
|
||||||
"1": self.thumbnail,
|
"1": self.thumbnail,
|
||||||
},
|
},
|
||||||
# TODO: The back has bad external id support, we disable it for now
|
|
||||||
"external_ids": None,
|
|
||||||
"show": None,
|
"show": None,
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user