Refactor ShowAudience handling across the application to align with MPAA rating system. Update ShowAudience enum to reflect new ratings (G, PG, PG-13, R, NC-17) and adjust related data models, API types, and frontend components to support nullable audience values. Enhance metadata handling to incorporate content ratings from external sources, ensuring proper audience filtering in scheduling logic. Update documentation to clarify changes in audience categorization and its implications for content management.
ci / build-backend (push) Successful in 1m28s
ci / build-frontend (push) Successful in 51s
ci / tests (push) Successful in 2m7s
ci / sonar (push) Successful in 4m31s

This commit is contained in:
Leonid Pershin
2026-07-26 22:18:14 +03:00
parent c4c93cff02
commit fdb0f321e4
34 changed files with 1868 additions and 116 deletions
@@ -3,6 +3,7 @@ using System.Text.Json;
using Microsoft.Extensions.Options;
using TeleWave.Application.Common.Interfaces;
using TeleWave.Application.Metadata;
using TeleWave.Domain.Library;
using static TeleWave.Infrastructure.Metadata.MetadataJson;
namespace TeleWave.Infrastructure.Metadata;
@@ -22,8 +23,10 @@ public sealed class OmdbMetadataProvider(
CancellationToken cancellationToken
)
{
var url =
$"{_omdb.BaseUrl}/?apikey={_omdb.ApiKey}&type=series&s={Uri.EscapeDataString(query)}";
// Тип в запросе не фиксируем: imdbID уникален и для фильма, и для сериала, а GetShowAsync
// ходит по нему же — значит полнометражки находятся и обогащаются тем же путём, без
// разделения пространств идентификаторов (в отличие от TMDb, где tv и movie нумеруются врозь).
var url = $"{_omdb.BaseUrl}/?apikey={_omdb.ApiKey}&s={Uri.EscapeDataString(query)}";
using var doc = await GetAsync(httpFactory, url, cancellationToken);
if (!doc.RootElement.TryGetProperty("Search", out var search))
return [];
@@ -34,13 +37,20 @@ public sealed class OmdbMetadataProvider(
var id = Clean(GetString(item, "imdbID"));
if (id is null)
continue;
// Отдельные серии в выдаче — шум: шоу из них не собирают, а список они забивают.
var kind = KindFrom(Clean(GetString(item, "Type")));
if (kind is null)
continue;
list.Add(
new MetadataCandidate(
id,
Clean(GetString(item, "Title")) ?? "—",
YearFrom(GetString(item, "Year")),
null,
Clean(GetString(item, "Poster"))
Clean(GetString(item, "Poster")),
kind
)
);
}
@@ -63,10 +73,22 @@ public sealed class OmdbMetadataProvider(
YearFrom(GetString(root, "Year")),
Clean(GetString(root, "Plot")),
Clean(GetString(root, "Poster")),
GenresFrom(Clean(GetString(root, "Genre")))
GenresFrom(Clean(GetString(root, "Genre"))),
// «Rated» приезжает только в ответе по id — то есть ровно здесь, без лишнего запроса.
// Отдаём как есть: приводить к шкале будет приложение (ContentRating).
Clean(GetString(root, "Rated"))
);
}
/// <summary>Тип из выдачи OMDb: «series»/«movie»; «episode» и незнакомое — null (в шоу не годятся).</summary>
private static ShowKind? KindFrom(string? type) =>
type?.ToLowerInvariant() switch
{
"series" => ShowKind.Series,
"movie" => ShowKind.Single,
_ => null,
};
/// <summary>OMDb отдаёт жанры одной строкой через запятую: «Action, Sci-Fi».</summary>
private static List<string> GenresFrom(string? value) =>
string.IsNullOrWhiteSpace(value)