Add missing seasons endpoint and update metadata handling
ci / build-backend (push) Successful in 4m7s
ci / build-frontend (push) Successful in 41s
ci / tests (push) Successful in 2m4s
ci / sonar (push) Successful in 4m41s

Implemented a new endpoint to retrieve missing seasons for shows, enhancing the MetadataEndpoints class. Updated the IMetadataProvider interface to include a method for fetching season numbers. Adjusted the ShowSummaryDto to include other genres and modified the ListShowsQueryHandler to handle multiple genres. Enhanced the Omdb and Tmdb metadata providers to support season number retrieval. Updated frontend components to integrate missing seasons functionality, including API calls and UI elements for displaying missing seasons reports.
This commit is contained in:
Leonid Pershin
2026-07-27 02:40:09 +03:00
parent 07c43a6875
commit 986f7ff52d
17 changed files with 540 additions and 53 deletions
@@ -144,6 +144,26 @@ public sealed class OmdbMetadataProvider(
return episodes.GetArrayLength();
}
/// <summary>
/// OMDb перечня сезонов не отдаёт — только их количество (<c>totalSeasons</c>, строкой) в ответе
/// по id. Считаем сезоны сплошной нумерацией с единицы: разрывов в ней у OMDb не бывает.
/// </summary>
public async Task<IReadOnlyList<int>> GetSeasonNumbersAsync(
string externalId,
CancellationToken cancellationToken
)
{
var url = $"{_omdb.BaseUrl}/?apikey={_omdb.ApiKey}&i={Uri.EscapeDataString(externalId)}";
using var doc = await TryGetAsync(httpFactory, url, cancellationToken);
if (doc is null || !IsResponseTrue(doc.RootElement))
return [];
var total = Clean(GetString(doc.RootElement, "totalSeasons"));
return int.TryParse(total, CultureInfo.InvariantCulture, out var count) && count > 0
? Enumerable.Range(1, count).ToList()
: [];
}
private static bool IsResponseTrue(JsonElement root) =>
GetString(root, "Response") is { } r
&& r.Equals("True", StringComparison.OrdinalIgnoreCase);
@@ -244,6 +244,32 @@ public sealed class TmdbMetadataProvider(
return episodes.GetArrayLength();
}
public async Task<IReadOnlyList<int>> GetSeasonNumbersAsync(
string externalId,
CancellationToken cancellationToken
)
{
var url =
$"{Tmdb.BaseUrl}/tv/{externalId}?api_key={Tmdb.ApiKey}&language={_options.Language}";
using var doc = await TryGetAsync(httpFactory, url, cancellationToken);
if (
doc is null
|| !doc.RootElement.TryGetProperty("seasons", out var seasons)
|| seasons.ValueKind != JsonValueKind.Array
)
return [];
var numbers = new List<int>();
foreach (var season in seasons.EnumerateArray())
{
// Нулевой сезон у TMDb — спецвыпуски; обычные сезоны нумеруются с единицы.
if (GetInt(season, "season_number") is { } number && number > 0)
numbers.Add(number);
}
numbers.Sort();
return numbers;
}
private string? PosterUrl(string? path) =>
string.IsNullOrEmpty(path) ? null : $"{Tmdb.ImageBaseUrl}/{Tmdb.PosterSize}{path}";