feat: restrict anime trailers, not all animation (v1.0.0.12)
All checks were successful
Publish Release / release (push) Successful in 9s

v1.0.0.11 kept every animated trailer away from non-animated content, which
also blocked Western animation (Pixar, Disney...). Only anime should be
restricted.

At download, a trailer is tagged ct4j-anime when TMDB has the "anime" or
"based on manga" keyword, or it is Animation in ja/zh/ko (keywords are now
appended to the details request). At playback, anime trailers are dropped
unless the feature is anime (genre "Anime", or those keywords as tags).
Western animation follows the normal genre/rating filters again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Martin
2026-10-05 17:57:12 -04:00
parent 205d64dc6f
commit d850e12964
6 changed files with 62 additions and 24 deletions

View File

@@ -19,7 +19,7 @@ namespace Jellyfin.Plugin.CinemaTrailers4Jellyfins.Services
public int? Year => DateTime.TryParse(ReleaseDate, out var d) ? d.Year : (int?)null;
}
public record TmdbMediaMetadata(IReadOnlyList<string> Genres, string? Certification);
public record TmdbMediaMetadata(IReadOnlyList<string> Genres, string? Certification, bool IsAnime);
public class TmdbService : IDisposable
{
@@ -236,7 +236,7 @@ namespace Jellyfin.Plugin.CinemaTrailers4Jellyfins.Services
try
{
var appendField = mediaType == "movie" ? "release_dates" : "content_ratings";
var url = $"{BaseUrl}/{mediaType}/{tmdbId}?append_to_response={appendField}&language=en-US";
var url = $"{BaseUrl}/{mediaType}/{tmdbId}?append_to_response={appendField},keywords&language=en-US";
using var request = new HttpRequestMessage(HttpMethod.Get, url);
ApplyAuth(request, apiKey);
using var response = await _httpClient.SendAsync(request, ct).ConfigureAwait(false);
@@ -262,16 +262,40 @@ namespace Jellyfin.Plugin.CinemaTrailers4Jellyfins.Services
? GetMovieCertification(doc)
: GetTvCertification(doc);
return new TmdbMediaMetadata(genres.AsReadOnly(), certification);
return new TmdbMediaMetadata(genres.AsReadOnly(), certification, IsAnime(doc, mediaType, genres));
}
catch (OperationCanceledException) { throw; }
catch (Exception ex)
{
_logger.LogError(ex, "|CinemaTrailers4Jellyfins| GetMediaMetadata failed for {MediaType} TMDB ID {Id}", mediaType, tmdbId);
return new TmdbMediaMetadata(Array.Empty<string>(), null);
return new TmdbMediaMetadata(Array.Empty<string>(), null, false);
}
}
private static readonly string[] AnimeKeywords = { "anime", "based on manga" };
private static readonly string[] AnimeLanguages = { "ja", "zh", "ko" };
// Anime vs. Western animation: both carry TMDB's "Animation" genre, so use the "anime" /
// "based on manga" keywords, or Animation made in Japanese, Chinese or Korean.
private static bool IsAnime(JsonDocument doc, string mediaType, List<string> genres)
{
// Movie keywords live under keywords.keywords, TV keywords under keywords.results.
var listName = mediaType == "movie" ? "keywords" : "results";
if (doc.RootElement.TryGetProperty("keywords", out var kw)
&& kw.TryGetProperty(listName, out var list)
&& list.ValueKind == JsonValueKind.Array
&& list.EnumerateArray().Any(k =>
k.TryGetProperty("name", out var n)
&& AnimeKeywords.Contains(n.GetString(), StringComparer.OrdinalIgnoreCase)))
{
return true;
}
return genres.Contains("Animation", StringComparer.OrdinalIgnoreCase)
&& doc.RootElement.TryGetProperty("original_language", out var lang)
&& AnimeLanguages.Contains(lang.GetString(), StringComparer.OrdinalIgnoreCase);
}
// Finds the US theatrical certification (G, PG, PG-13, R, NC-17) from release_dates.
private static string? GetMovieCertification(JsonDocument doc)
{