Fixing some issues

This commit is contained in:
Zoe Roux 2021-07-28 22:23:37 +02:00
parent 75b97c0150
commit 0c594a92c6
15 changed files with 70 additions and 26 deletions

View File

@ -63,7 +63,7 @@ namespace Kyoo.Models
/// This can be disabled using the internal query flag. /// This can be disabled using the internal query flag.
/// </summary> /// </summary>
[SerializeAs("{HOST}/api/{Type:l}/{Slug}/poster")] [SerializeAs("{HOST}/api/{Type:l}/{Slug}/poster")]
public string Poster => Images[Thumbnails.Poster]; public string Poster => Images?.GetValueOrDefault(Thumbnails.Poster);
/// <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).

View File

@ -30,7 +30,7 @@ namespace Kyoo.Models
/// This can be disabled using the internal query flag. /// This can be disabled using the internal query flag.
/// </summary> /// </summary>
[SerializeAs("{HOST}/api/collection/{Slug}/poster")] [SerializeAs("{HOST}/api/collection/{Slug}/poster")]
public string Poster => Images[Thumbnails.Poster]; public string Poster => Images?.GetValueOrDefault(Thumbnails.Poster);
/// <summary> /// <summary>
/// The description of this collection. /// The description of this collection.

View File

@ -108,7 +108,7 @@ namespace Kyoo.Models
/// This can be disabled using the internal query flag. /// This can be disabled using the internal query flag.
/// </summary> /// </summary>
[SerializeAs("{HOST}/api/episodes/{Slug}/thumb")] [SerializeAs("{HOST}/api/episodes/{Slug}/thumb")]
public string Thumb => Images[Thumbnails.Thumbnail]; public string Thumb => Images?.GetValueOrDefault(Thumbnails.Thumbnail);
/// <summary> /// <summary>
/// The title of this episode. /// The title of this episode.

View File

@ -28,7 +28,7 @@ namespace Kyoo.Models
/// This can be disabled using the internal query flag. /// This can be disabled using the internal query flag.
/// </summary> /// </summary>
[SerializeAs("{HOST}/api/people/{Slug}/poster")] [SerializeAs("{HOST}/api/people/{Slug}/poster")]
public string Poster => Images[Thumbnails.Poster]; public string Poster => Images?.GetValueOrDefault(Thumbnails.Poster);
/// <inheritdoc /> /// <inheritdoc />
[EditableRelation] [LoadableRelation] public ICollection<MetadataID> ExternalIDs { get; set; } [EditableRelation] [LoadableRelation] public ICollection<MetadataID> ExternalIDs { get; set; }

View File

@ -31,7 +31,7 @@ namespace Kyoo.Models
/// This can be disabled using the internal query flag. /// This can be disabled using the internal query flag.
/// </summary> /// </summary>
[SerializeAs("{HOST}/api/providers/{Slug}/logo")] [SerializeAs("{HOST}/api/providers/{Slug}/logo")]
public string Logo => Images[Thumbnails.Logo]; public string Logo => Images?.GetValueOrDefault(Thumbnails.Logo);
/// <summary> /// <summary>
/// The extension of the logo. This is used for http responses. /// The extension of the logo. This is used for http responses.

View File

@ -83,7 +83,7 @@ namespace Kyoo.Models
/// This can be disabled using the internal query flag. /// This can be disabled using the internal query flag.
/// </summary> /// </summary>
[SerializeAs("{HOST}/api/seasons/{Slug}/thumb")] [SerializeAs("{HOST}/api/seasons/{Slug}/thumb")]
public string Poster => Images[Thumbnails.Poster]; public string Poster => Images?.GetValueOrDefault(Thumbnails.Poster);
/// <inheritdoc /> /// <inheritdoc />
[EditableRelation] [LoadableRelation] public ICollection<MetadataID> ExternalIDs { get; set; } [EditableRelation] [LoadableRelation] public ICollection<MetadataID> ExternalIDs { get; set; }

View File

@ -1,7 +1,5 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using Kyoo.Common.Models.Attributes; using Kyoo.Common.Models.Attributes;
using Kyoo.Controllers; using Kyoo.Controllers;
using Kyoo.Models.Attributes; using Kyoo.Models.Attributes;
@ -49,7 +47,7 @@ namespace Kyoo.Models
/// An URL to a trailer. This could be any path supported by the <see cref="IFileSystem"/>. /// An URL to a trailer. This could be any path supported by the <see cref="IFileSystem"/>.
/// </summary> /// </summary>
/// TODO for now, this is set to a youtube url. It should be cached and converted to a local file. /// TODO for now, this is set to a youtube url. It should be cached and converted to a local file.
public string TrailerUrl => Images[Thumbnails.Trailer]; public string TrailerUrl => Images?.GetValueOrDefault(Thumbnails.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.
@ -72,7 +70,7 @@ namespace Kyoo.Models
/// This can be disabled using the internal query flag. /// This can be disabled using the internal query flag.
/// </summary> /// </summary>
[SerializeAs("{HOST}/api/shows/{Slug}/poster")] [SerializeAs("{HOST}/api/shows/{Slug}/poster")]
public string Poster => Images[Thumbnails.Poster]; public string Poster => Images?.GetValueOrDefault(Thumbnails.Poster);
/// <summary> /// <summary>
/// The path of this show's logo. /// The path of this show's logo.
@ -80,7 +78,7 @@ namespace Kyoo.Models
/// This can be disabled using the internal query flag. /// This can be disabled using the internal query flag.
/// </summary> /// </summary>
[SerializeAs("{HOST}/api/shows/{Slug}/logo")] [SerializeAs("{HOST}/api/shows/{Slug}/logo")]
public string Logo => Images[Thumbnails.Logo]; public string Logo => Images?.GetValueOrDefault(Thumbnails.Logo);
/// <summary> /// <summary>
/// The path of this show's backdrop. /// The path of this show's backdrop.
@ -88,7 +86,7 @@ namespace Kyoo.Models
/// This can be disabled using the internal query flag. /// This can be disabled using the internal query flag.
/// </summary> /// </summary>
[SerializeAs("{HOST}/api/shows/{Slug}/backdrop")] [SerializeAs("{HOST}/api/shows/{Slug}/backdrop")]
public string Backdrop => Images[Thumbnails.Thumbnail]; public string Backdrop => Images?.GetValueOrDefault(Thumbnails.Thumbnail);
/// <summary> /// <summary>
/// True if this show represent a movie, false otherwise. /// True if this show represent a movie, false otherwise.

View File

@ -165,7 +165,7 @@ namespace Kyoo.SqLite.Migrations
INNER JOIN Collections AS c ON l.FirstID = c.ID INNER JOIN Collections AS c ON l.FirstID = c.ID
WHERE s.ID = l.SecondID)) WHERE s.ID = l.SecondID))
UNION ALL UNION ALL
SELECT -c0.ID, c0.Slug, c0.Name AS Title, c0.Overview, 3 AS Status, SELECT -c0.ID, c0.Slug, c0.Name AS Title, c0.Overview, 0 AS Status,
NULL AS StartAir, NULL AS EndAir, c0.Images, 2 AS Type NULL AS StartAir, NULL AS EndAir, c0.Images, 2 AS Type
FROM collections AS c0"); FROM collections AS c0");
} }

View File

@ -55,7 +55,7 @@ namespace Kyoo.Tests.Database
[Fact] [Fact]
public async Task GetCollectionTests() public async Task GetCollectionTests()
{ {
LibraryItem expected = new(TestSample.Get<Show>()); LibraryItem expected = new(TestSample.Get<Collection>());
LibraryItem actual = await _repository.Get(-1); LibraryItem actual = await _repository.Get(-1);
KAssert.DeepEqual(expected, actual); KAssert.DeepEqual(expected, actual);
} }

View File

@ -235,6 +235,39 @@ namespace Kyoo.Tests.Database
expected.Studio = new Studio("studio"); expected.Studio = new Studio("studio");
Show created = await _repository.Create(expected); Show created = await _repository.Create(expected);
KAssert.DeepEqual(expected, created); KAssert.DeepEqual(expected, created);
await using DatabaseContext context = Repositories.Context.New();
Show retrieved = await context.Shows
.Include(x => x.ExternalIDs)
.Include(x => x.Genres)
.Include(x => x.People)
.Include(x => x.Studio)
.FirstAsync(x => x.ID == created.ID);
KAssert.DeepEqual(expected, retrieved);
}
[Fact]
public async Task CreateWithExternalID()
{
Show expected = TestSample.Get<Show>();
expected.ID = 0;
expected.Slug = "created-relation-test";
expected.ExternalIDs = new[]
{
new MetadataID
{
Provider = TestSample.Get<Provider>(),
DataID = "ID"
}
};
Show created = await _repository.Create(expected);
KAssert.DeepEqual(expected, created);
await using DatabaseContext context = Repositories.Context.New();
Show retrieved = await context.Shows
.Include(x => x.ExternalIDs)
.FirstAsync(x => x.ID == created.ID);
KAssert.DeepEqual(expected, retrieved);
Assert.Equal(1, retrieved.ExternalIDs.Count);
Assert.Equal("ID", retrieved.ExternalIDs.First().DataID);
} }
[Fact] [Fact]

View File

@ -1,3 +1,5 @@
using System.Collections;
using System.Linq;
using System.Reflection; using System.Reflection;
using JetBrains.Annotations; using JetBrains.Annotations;
using Xunit; using Xunit;
@ -19,8 +21,11 @@ namespace Kyoo.Tests
[AssertionMethod] [AssertionMethod]
public static void DeepEqual<T>(T expected, T value) public static void DeepEqual<T>(T expected, T value)
{ {
foreach (PropertyInfo property in typeof(T).GetProperties(BindingFlags.Instance)) PropertyInfo[] properties = typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public);
foreach (PropertyInfo property in properties)
Assert.Equal(property.GetValue(expected), property.GetValue(value)); Assert.Equal(property.GetValue(expected), property.GetValue(value));
if (!properties.Any())
Assert.Equal(expected, value);
} }
/// <summary> /// <summary>

View File

@ -44,7 +44,6 @@ namespace Kyoo.TheMovieDb
Studio = !string.IsNullOrEmpty(tv.ProductionCompanies.FirstOrDefault()?.Name) Studio = !string.IsNullOrEmpty(tv.ProductionCompanies.FirstOrDefault()?.Name)
? new Studio(tv.ProductionCompanies.First().Name) ? new Studio(tv.ProductionCompanies.First().Name)
: null, : null,
IsMovie = true,
People = tv.Credits.Cast People = tv.Credits.Cast
.Select(x => x.ToPeople(provider)) .Select(x => x.ToPeople(provider))
.Concat(tv.Credits.Crew.Select(x => x.ToPeople(provider))) .Concat(tv.Credits.Crew.Select(x => x.ToPeople(provider)))
@ -84,7 +83,6 @@ namespace Kyoo.TheMovieDb
? $"https://image.tmdb.org/t/p/original{tv.BackdropPath}" ? $"https://image.tmdb.org/t/p/original{tv.BackdropPath}"
: null, : null,
}, },
IsMovie = true,
ExternalIDs = new [] ExternalIDs = new []
{ {
new MetadataID new MetadataID

View File

@ -122,12 +122,16 @@ namespace Kyoo.TheMovieDb
/// <returns>A season containing metadata from TheMovieDb</returns> /// <returns>A season containing metadata from TheMovieDb</returns>
private async Task<Season> _GetSeason(Season season) private async Task<Season> _GetSeason(Season season)
{ {
if (season.Show == null || !season.Show.TryGetID(Provider.Slug, out int id)) if (season.Show == null)
{ {
_logger.LogWarning("Metadata for a season was requested but it's show is not loaded. " + _logger.LogWarning("Metadata for a season was requested but it's show is not loaded. " +
"This is unsupported"); "This is unsupported");
return null; return null;
} }
if (!season.Show.TryGetID(Provider.Slug, out int id))
return null;
TMDbClient client = new(_apiKey.Value.ApiKey); TMDbClient client = new(_apiKey.Value.ApiKey);
return (await client.GetTvSeasonAsync(id, season.SeasonNumber)) return (await client.GetTvSeasonAsync(id, season.SeasonNumber))
.ToSeason(id, Provider); .ToSeason(id, Provider);
@ -141,13 +145,14 @@ namespace Kyoo.TheMovieDb
/// <returns>An episode containing metadata from TheMovieDb</returns> /// <returns>An episode containing metadata from TheMovieDb</returns>
private async Task<Episode> _GetEpisode(Episode episode) private async Task<Episode> _GetEpisode(Episode episode)
{ {
if (episode.Show == null || !episode.Show.TryGetID(Provider.Slug, out int id)) if (episode.Show == null)
{ {
_logger.LogWarning("Metadata for a season was requested but it's show is not loaded. " + _logger.LogWarning("Metadata for an episode was requested but it's show is not loaded. " +
"This is unsupported"); "This is unsupported");
return null; return null;
} }
if (episode.SeasonNumber == null || episode.EpisodeNumber == null) if (!episode.Show.TryGetID(Provider.Slug, out int id)
|| episode.SeasonNumber == null || episode.EpisodeNumber == null)
return null; return null;
TMDbClient client = new(_apiKey.Value.ApiKey); TMDbClient client = new(_apiKey.Value.ApiKey);

View File

@ -1,6 +1,7 @@
using Kyoo.Models; using Kyoo.Models;
using System; using System;
using System.IO; using System.IO;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Kyoo.Models.Options; using Kyoo.Models.Options;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
@ -87,10 +88,13 @@ namespace Kyoo.Controllers
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; bool ret = false;
foreach ((int id, string image) in item.Images) foreach ((int id, string image) in item.Images.Where(x => x.Value != null))
{ {
string localPath = await GetImagePath(item, id); string localPath = await GetImagePath(item, id);
if (alwaysDownload || !await _files.Exists(localPath)) if (alwaysDownload || !await _files.Exists(localPath))

View File

@ -116,9 +116,6 @@ namespace Kyoo.Tasks
else else
show = registeredShow; show = registeredShow;
// If they are not already loaded, load external ids to allow metadata providers to use them.
if (show.ExternalIDs == null)
await _libraryManager.Load(show, x => x.ExternalIDs);
progress.Report(50); progress.Report(50);
if (season != null) if (season != null)
@ -163,14 +160,18 @@ namespace Kyoo.Tasks
/// <typeparam name="T">The type of the item</typeparam> /// <typeparam name="T">The type of the item</typeparam>
/// <returns>The existing or filled item.</returns> /// <returns>The existing or filled item.</returns>
private async Task<T> _RegisterAndFill<T>(T item) private async Task<T> _RegisterAndFill<T>(T item)
where T : class, IResource, IThumbnails where T : class, IResource, IThumbnails, IMetadata
{ {
if (item == null || string.IsNullOrEmpty(item.Slug)) if (item == null || string.IsNullOrEmpty(item.Slug))
return null; return null;
T existing = await _libraryManager.GetOrDefault<T>(item.Slug); T existing = await _libraryManager.GetOrDefault<T>(item.Slug);
if (existing != null) if (existing != null)
{
await _libraryManager.Load(existing, x => x.ExternalIDs);
return existing; return existing;
}
item = await _metadataProvider.Get(item); item = await _metadataProvider.Get(item);
await _thumbnailsManager.DownloadImages(item); await _thumbnailsManager.DownloadImages(item);
return await _libraryManager.CreateIfNotExists(item); return await _libraryManager.CreateIfNotExists(item);