Merge pull request #21 from pikami/feature/20-Episode-metadata-does-not-get-filled

This commit is contained in:
Cody Robibero 2022-06-12 08:00:16 -06:00 committed by GitHub
commit 7a097bdc79
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 164 additions and 123 deletions

View File

@ -1,105 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;
namespace Jellyfin.Plugin.Anime.Providers.KitsuIO.ApiClient
{
public class ApiListResponse
{
public List<Series> Data { get; set; }
public ResponseMeta Meta { get; set; }
}
public class ApiResponse
{
public Series Data { get; set; }
public List<Included> Included { get; set; }
}
public class Series
{
public long Id { get; set; }
public Attributes Attributes { get; set; }
}
public class Attributes
{
public string Synopsis { get; set; }
public Titles Titles { get; set; }
public string AverageRating { get; set; }
public DateTimeOffset? StartDate { get; set; }
public PosterImage PosterImage { get; set; }
// Episode specific
public int? Number { get; set; }
public int? SeasonNumber { get; set; }
public DateTime? AirDate { get; set; }
public int? Length { get; set; }
}
public class PosterImage
{
public Uri Medium { get; set; }
public Uri Original { get; set; }
}
public class Titles
{
[JsonPropertyName("en")] public string En { get; set; }
[JsonPropertyName("en_jp")] public string EnJp { get; set; }
[JsonPropertyName("ja_jp")] public string JaJp { get; set; }
[JsonPropertyName("en_us")] public string EnUs { get; set; }
public string GetTitle =>
!string.IsNullOrWhiteSpace(En) ? En :
!string.IsNullOrWhiteSpace(EnUs) ? EnUs :
!string.IsNullOrWhiteSpace(EnJp) ? EnJp :
JaJp;
public bool Equal(string title)
{
return
(En?.Equals(title) ?? false) ||
(EnUs?.Equals(title) ?? false) ||
(EnJp?.Equals(title) ?? false) ||
(JaJp?.Equals(title) ?? false);
}
}
public class ResponseMeta
{
public long? Count { get; set; }
}
public class Included
{
public IncludedAttributes Attributes { get; set; }
}
public class IncludedAttributes
{
public string Name { get; set; }
}
public enum ShowTypeEnum
{
Movie,
Ova,
Ona,
Tv,
Music,
Special
}
public enum Status
{
Current,
Finished,
Tba,
Unreleased,
Upcoming
}
}

View File

@ -1,3 +1,4 @@
using Jellyfin.Plugin.Kitsu.Providers.KitsuIO.ApiClient.Models;
using MediaBrowser.Common.Net;
using System.Collections.Generic;
using System.Linq;
@ -16,7 +17,6 @@ namespace Jellyfin.Plugin.Anime.Providers.KitsuIO.ApiClient
static KitsuIoApi()
{
_serializerOptions = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true,
@ -25,7 +25,7 @@ namespace Jellyfin.Plugin.Anime.Providers.KitsuIO.ApiClient
_serializerOptions.Converters.Add(new JsonStringEnumConverter(JsonNamingPolicy.CamelCase));
}
public static async Task<ApiListResponse> Search_Series(Dictionary<string, string> filters, IHttpClientFactory httpClientFactory)
public static async Task<ApiResponse<List<KitsuSeries>>> Search_Series(Dictionary<string, string> filters, IHttpClientFactory httpClientFactory)
{
var filterString = string.Join("&",filters.Select(x => $"filter[{x.Key}]={x.Value}"));
var pageString = "page[limit]=10";
@ -34,21 +34,21 @@ namespace Jellyfin.Plugin.Anime.Providers.KitsuIO.ApiClient
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/vnd.api+json"));
var responseStream = await httpClient.GetStreamAsync($"{_apiBaseUrl}/anime?{filterString}&{pageString}");
return await JsonSerializer.DeserializeAsync<ApiListResponse>(responseStream, _serializerOptions);
return await JsonSerializer.DeserializeAsync<ApiResponse<List<KitsuSeries>>>(responseStream, _serializerOptions);
}
public static async Task<ApiResponse> Get_Series(string seriesId, IHttpClientFactory httpClientFactory)
public static async Task<ApiResponse<KitsuSeries>> Get_Series(string seriesId, IHttpClientFactory httpClientFactory)
{
var httpClient = httpClientFactory.CreateClient(NamedClient.Default);
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/vnd.api+json"));
var responseStream = await httpClient.GetStreamAsync($"{_apiBaseUrl}/anime/{seriesId}?include=genres");
return await JsonSerializer.DeserializeAsync<ApiResponse>(responseStream, _serializerOptions);
return await JsonSerializer.DeserializeAsync<ApiResponse<KitsuSeries>>(responseStream, _serializerOptions);
}
public static async Task<ApiListResponse> Get_Episodes(string seriesId, IHttpClientFactory httpClientFactory)
public static async Task<ApiResponse<List<KitsuEpisode>>> Get_Episodes(string seriesId, IHttpClientFactory httpClientFactory)
{
var result = new ApiListResponse();
var result = new ApiResponse<List<KitsuEpisode>>(new List<KitsuEpisode>());
long episodeCount = 10;
var step = 10;
@ -59,7 +59,7 @@ namespace Jellyfin.Plugin.Anime.Providers.KitsuIO.ApiClient
{
var queryString = $"?filter[mediaId]={seriesId}&page[limit]={step}&page[offset]={offset}";
var responseStream = await httpClient.GetStreamAsync($"{_apiBaseUrl}/episodes{queryString}");
var response = await JsonSerializer.DeserializeAsync<ApiListResponse>(responseStream, _serializerOptions);
var response = await JsonSerializer.DeserializeAsync<ApiResponse<List<KitsuEpisode>>>(responseStream, _serializerOptions);
episodeCount = response.Meta.Count.Value;
result.Data.AddRange(response.Data);
@ -68,7 +68,7 @@ namespace Jellyfin.Plugin.Anime.Providers.KitsuIO.ApiClient
return result;
}
public static async Task<ApiResponse> Get_Episode(string episodeId, IHttpClientFactory httpClientFactory)
public static async Task<ApiResponse<KitsuEpisode>> Get_Episode(string episodeId, IHttpClientFactory httpClientFactory)
{
var filterString = $"/{episodeId}";
@ -76,7 +76,25 @@ namespace Jellyfin.Plugin.Anime.Providers.KitsuIO.ApiClient
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/vnd.api+json"));
var responseStream = await httpClient.GetStreamAsync($"{_apiBaseUrl}/episodes{filterString}");
return await JsonSerializer.DeserializeAsync<ApiResponse>(responseStream, _serializerOptions);
return await JsonSerializer.DeserializeAsync<ApiResponse<KitsuEpisode>>(responseStream, _serializerOptions);
}
public static async Task<ApiResponse<KitsuEpisode>> Get_Episode(string seriesId, int episodeNumber, IHttpClientFactory httpClientFactory)
{
var queryString = $"?filter[mediaId]={seriesId}&filter[number]={episodeNumber}";
var httpClient = httpClientFactory.CreateClient(NamedClient.Default);
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/vnd.api+json"));
var responseStream = await httpClient.GetStreamAsync($"{_apiBaseUrl}/episodes{queryString}");
var response = await JsonSerializer.DeserializeAsync<ApiResponse<List<KitsuEpisode>>>(responseStream, _serializerOptions);
return new ApiResponse<KitsuEpisode>
{
Data = response.Data.FirstOrDefault(),
Included = response.Included,
Meta = response.Meta
};
}
}
}

View File

@ -0,0 +1,18 @@
using System.Collections.Generic;
namespace Jellyfin.Plugin.Kitsu.Providers.KitsuIO.ApiClient.Models
{
public class ApiResponse<T>
{
public T Data { get; set; }
public List<Included> Included { get; set; }
public ResponseMeta Meta { get; set; }
public ApiResponse() { }
public ApiResponse(T initialData)
{
Data = initialData;
}
}
}

View File

@ -0,0 +1,7 @@
namespace Jellyfin.Plugin.Kitsu.Providers.KitsuIO.ApiClient.Models
{
public class Included
{
public IncludedAttributes Attributes { get; set; }
}
}

View File

@ -0,0 +1,7 @@
namespace Jellyfin.Plugin.Kitsu.Providers.KitsuIO.ApiClient.Models
{
public class IncludedAttributes
{
public string Name { get; set; }
}
}

View File

@ -0,0 +1,8 @@
namespace Jellyfin.Plugin.Kitsu.Providers.KitsuIO.ApiClient.Models
{
public class KitsuEpisode
{
public long Id { get; set; }
public KitsuEpisodeAttributes Attributes { get; set; }
}
}

View File

@ -0,0 +1,15 @@
using System;
namespace Jellyfin.Plugin.Kitsu.Providers.KitsuIO.ApiClient.Models
{
public class KitsuEpisodeAttributes
{
public string Synopsis { get; set; }
public KitsuTitles Titles { get; set; }
public int? Number { get; set; }
public int? SeasonNumber { get; set; }
public DateTime? AirDate { get; set; }
public int? Length { get; set; }
public KitsuImage Thumbnail { get; set; }
}
}

View File

@ -0,0 +1,10 @@
using System;
namespace Jellyfin.Plugin.Kitsu.Providers.KitsuIO.ApiClient.Models
{
public class KitsuImage
{
public Uri Medium { get; set; }
public Uri Original { get; set; }
}
}

View File

@ -0,0 +1,8 @@
namespace Jellyfin.Plugin.Kitsu.Providers.KitsuIO.ApiClient.Models
{
public class KitsuSeries
{
public long Id { get; set; }
public KitsuSeriesAttributes Attributes { get; set; }
}
}

View File

@ -0,0 +1,14 @@
using System;
namespace Jellyfin.Plugin.Kitsu.Providers.KitsuIO.ApiClient.Models
{
public class KitsuSeriesAttributes
{
public string Synopsis { get; set; }
public KitsuTitles Titles { get; set; }
public string AverageRating { get; set; }
public DateTimeOffset? StartDate { get; set; }
public KitsuImage PosterImage { get; set; }
public KitsuImage CoverImage { get; set; }
}
}

View File

@ -0,0 +1,7 @@
namespace Jellyfin.Plugin.Kitsu.Providers.KitsuIO.ApiClient.Models
{
public class ResponseMeta
{
public long? Count { get; set; }
}
}

View File

@ -0,0 +1,26 @@
using System.Collections.Generic;
using System.Linq;
using System.Text.Json.Serialization;
namespace Jellyfin.Plugin.Kitsu.Providers.KitsuIO.ApiClient.Models
{
public class KitsuTitles
{
[JsonPropertyName("en")] public string En { get; set; }
[JsonPropertyName("en_jp")] public string EnJp { get; set; }
[JsonPropertyName("ja_jp")] public string JaJp { get; set; }
[JsonPropertyName("en_us")] public string EnUs { get; set; }
public IEnumerable<string> GetTitlesOrderedByPriority() => new [] { En, EnUs, EnJp, JaJp }
.Where(title => !string.IsNullOrWhiteSpace(title));
public string GetTitle =>
GetTitlesOrderedByPriority().FirstOrDefault();
public bool Equal(string title) =>
GetTitlesOrderedByPriority().Contains(title);
}
}

View File

@ -47,13 +47,16 @@ namespace Jellyfin.Plugin.Anime.Providers.KitsuIO.Metadata
{
var result = new MetadataResult<Episode>();
var id = info.ProviderIds.GetValueOrDefault("Kitsu");
if (string.IsNullOrWhiteSpace(id))
if (!info.SeriesProviderIds.TryGetValue("Kitsu", out var seriesId) || !info.IndexNumber.HasValue)
{
return result;
}
var episodeInfo = await KitsuIoApi.Get_Episode(id, _httpClientFactory);
var episodeInfo = await KitsuIoApi.Get_Episode(seriesId, info.IndexNumber.Value, _httpClientFactory);
if (episodeInfo?.Data?.Attributes == null)
{
return result;
}
result.HasMetadata = true;
result.Item = new Episode
@ -61,6 +64,9 @@ namespace Jellyfin.Plugin.Anime.Providers.KitsuIO.Metadata
IndexNumber = info.IndexNumber,
ParentIndexNumber = info.ParentIndexNumber,
Name = episodeInfo.Data.Attributes.Titles.GetTitle,
PremiereDate = episodeInfo.Data.Attributes.AirDate,
Overview = episodeInfo.Data.Attributes.Synopsis,
ProviderIds = new Dictionary<string, string>() { { "Kitsu", episodeInfo.Data.Id.ToString() } }
};
if (episodeInfo.Data.Attributes.Length != null)

View File

@ -13,10 +13,12 @@ using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Providers;
using Microsoft.Extensions.Logging;
using MediaBrowser.Controller.Entities.TV;
using Jellyfin.Plugin.Kitsu.Providers.KitsuIO.ApiClient.Models;
namespace Jellyfin.Plugin.Anime.Providers.KitsuIO.Metadata
{
public class KitsuIoSeriesProvider : IRemoteMetadataProvider<MediaBrowser.Controller.Entities.TV.Series, SeriesInfo>, IHasOrder
public class KitsuIoSeriesProvider : IRemoteMetadataProvider<Series, SeriesInfo>, IHasOrder
{
private readonly ILogger<KitsuIoSeriesProvider> _log;
private readonly IApplicationPaths _paths;
@ -58,9 +60,9 @@ namespace Jellyfin.Plugin.Anime.Providers.KitsuIO.Metadata
return searchResults;
}
public async Task<MetadataResult<MediaBrowser.Controller.Entities.TV.Series>> GetMetadata(SeriesInfo info, CancellationToken cancellationToken)
public async Task<MetadataResult<Series>> GetMetadata(SeriesInfo info, CancellationToken cancellationToken)
{
var result = new MetadataResult<MediaBrowser.Controller.Entities.TV.Series>();
var result = new MetadataResult<Series>();
var kitsuId = info.ProviderIds.GetValueOrDefault("Kitsu");
if (string.IsNullOrWhiteSpace(kitsuId))
@ -75,7 +77,7 @@ namespace Jellyfin.Plugin.Anime.Providers.KitsuIO.Metadata
{
var seriesInfo = await KitsuIoApi.Get_Series(kitsuId, _httpClientFactory);
result.HasMetadata = true;
result.Item = new MediaBrowser.Controller.Entities.TV.Series
result.Item = new Series
{
Overview = seriesInfo.Data.Attributes.Synopsis,
// KitsuIO has a max rating of 100
@ -116,7 +118,7 @@ namespace Jellyfin.Plugin.Anime.Providers.KitsuIO.Metadata
File.WriteAllText(path, url);
}
private RemoteSearchResult MapToRemoteSearchResult(Series series)
private RemoteSearchResult MapToRemoteSearchResult(KitsuSeries series)
{
var parsedSeries = new RemoteSearchResult
{