From b493c9cd5226de9e4a62bfb64cc1abc6f6088546 Mon Sep 17 00:00:00 2001 From: imSp4rky Date: Fri, 30 Oct 2026 17:28:50 -0600 Subject: [PATCH] fix(naming): tag HDR10+ from the track range when MediaInfo misses it --- tests/core/test_hdr10p_naming.py | 53 ++++++++++++++++++++++++++++++++ unshackle/core/titles/title.py | 4 ++- 2 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 tests/core/test_hdr10p_naming.py diff --git a/tests/core/test_hdr10p_naming.py b/tests/core/test_hdr10p_naming.py new file mode 100644 index 00000000..981969ef --- /dev/null +++ b/tests/core/test_hdr10p_naming.py @@ -0,0 +1,53 @@ +"""Tests for the HDR tag in the filename context when MediaInfo misses HDR10+.""" + +from __future__ import annotations + +import types + +import pytest + +from unshackle.core.config import config +from unshackle.core.titles.movie import Movie +from unshackle.core.tracks import Tracks, Video + + +class DummyService: + pass + + +@pytest.fixture(autouse=True) +def clean_config(monkeypatch: pytest.MonkeyPatch) -> None: + monkeypatch.setattr(config, "tag_rules", []) + monkeypatch.setattr(config, "language_tags", {}) + monkeypatch.setattr(config, "codec_names", {}) + + +def hdr_tag(commercial: str, range_: Video.Range) -> str: + movie = Movie(id_="movie-0001", service=DummyService, name="The Film", year=2024, language="en") + movie.tracks = Tracks(Video(url="https://example.test/v.mpd", language="en", codec=Video.Codec.AV1, range_=range_)) + video = types.SimpleNamespace( + width=1920, + height=1080, + format="AV1", + scan_type="Progressive", + other_display_aspect_ratio=["16:9"], + hdr_format_commercial=commercial, + hdr_format="SMPTE ST 2086", + transfer_characteristics="PQ", + transfer_characteristics_original=None, + frame_rate="23.976", + ) + media_info = types.SimpleNamespace(video_tracks=[video], audio_tracks=[]) + return str(movie.build_base_template_context(media_info)["hdr"]) + + +def test_an_hdr10p_track_upgrades_a_plain_hdr10_tag() -> None: + assert hdr_tag("HDR10", Video.Range.HDR10P) == "HDR10P" + + +def test_an_hdr10_track_keeps_the_hdr_tag() -> None: + assert hdr_tag("HDR10", Video.Range.HDR10) == "HDR" + + +def test_mediainfo_hdr10p_is_unchanged() -> None: + assert hdr_tag("HDR10 / HDR10+", Video.Range.HDR10) == "HDR10P" diff --git a/unshackle/core/titles/title.py b/unshackle/core/titles/title.py index 48586ea3..ebfbe0d4 100644 --- a/unshackle/core/titles/title.py +++ b/unshackle/core/titles/title.py @@ -13,7 +13,7 @@ from unshackle.core.constants import ( SPACED_AUDIO_CODECS, VIDEO_CODEC_MAP, ) -from unshackle.core.tracks import Tracks +from unshackle.core.tracks import Tracks, Video from unshackle.core.utilities import spoken_language @@ -167,6 +167,8 @@ class Title: context["hdr"] = "HDR" else: context["hdr"] = DYNAMIC_RANGE_MAP.get(hdr_format, "") + if context["hdr"] == "HDR" and any(v.range == Video.Range.HDR10P for v in self.tracks.videos[:1]): + context["hdr"] = DYNAMIC_RANGE_MAP["HDR10+"] elif trc and "HLG" in trc: context["hdr"] = "HLG" else: