From 597a8b791208f93067c8ea2bb85daca48b8539ff Mon Sep 17 00:00:00 2001 From: Andy Date: Sun, 2 Nov 2025 03:19:14 +0000 Subject: [PATCH] fix(naming): improve HDR detection with comprehensive transfer checks and hybrid DV+HDR10 support HDR10/PQ detection now includes: - PQ (most common) - SMPTE ST 2084 (CICP value 16) - BT.2100 - BT.2020-10 - smpte2084 (lowercase variant) HLG detection now includes: - HLG - Hybrid Log-Gamma - ARIB STD-B67 (CICP value 18) - arib-std-b67 (lowercase variant) Hybrid DV+HDR10 detection: - Now checks full hdr_format field for both "Dolby Vision" AND ("HDR10" OR "SMPTE ST 2086") - Properly generates filenames like "Movie.2160p.DV HDR H.265.mkv" - MediaInfo reports: "Dolby Vision / SMPTE ST 2086, HDR10 compatible" Also adds null safety for transfer characteristics to prevent errors when the field is None. --- unshackle/core/titles/episode.py | 12 +++++++++--- unshackle/core/titles/movie.py | 12 +++++++++--- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/unshackle/core/titles/episode.py b/unshackle/core/titles/episode.py index 85ad7ac..6592b60 100644 --- a/unshackle/core/titles/episode.py +++ b/unshackle/core/titles/episode.py @@ -173,20 +173,26 @@ class Episode(Title): if primary_video_track: codec = primary_video_track.format hdr_format = primary_video_track.hdr_format_commercial + hdr_format_full = primary_video_track.hdr_format or "" trc = ( primary_video_track.transfer_characteristics or primary_video_track.transfer_characteristics_original + or "" ) frame_rate = float(primary_video_track.frame_rate) + + # Primary HDR format detection if hdr_format: - if (primary_video_track.hdr_format or "").startswith("Dolby Vision"): + if hdr_format_full.startswith("Dolby Vision"): name += " DV" - if DYNAMIC_RANGE_MAP.get(hdr_format) and DYNAMIC_RANGE_MAP.get(hdr_format) != "DV": + if any(indicator in hdr_format_full for indicator in ["HDR10", "SMPTE ST 2086"]): name += " HDR" else: name += f" {DYNAMIC_RANGE_MAP.get(hdr_format)} " - elif trc and "HLG" in trc: + elif "HLG" in trc or "Hybrid Log-Gamma" in trc or "ARIB STD-B67" in trc or "arib-std-b67" in trc.lower(): name += " HLG" + elif any(indicator in trc for indicator in ["PQ", "SMPTE ST 2084", "BT.2100"]) or "smpte2084" in trc.lower() or "bt.2020-10" in trc.lower(): + name += " HDR" if frame_rate > 30: name += " HFR" name += f" {VIDEO_CODEC_MAP.get(codec, codec)}" diff --git a/unshackle/core/titles/movie.py b/unshackle/core/titles/movie.py index cd153b6..1545b18 100644 --- a/unshackle/core/titles/movie.py +++ b/unshackle/core/titles/movie.py @@ -124,20 +124,26 @@ class Movie(Title): if primary_video_track: codec = primary_video_track.format hdr_format = primary_video_track.hdr_format_commercial + hdr_format_full = primary_video_track.hdr_format or "" trc = ( primary_video_track.transfer_characteristics or primary_video_track.transfer_characteristics_original + or "" ) frame_rate = float(primary_video_track.frame_rate) + + # Primary HDR format detection if hdr_format: - if (primary_video_track.hdr_format or "").startswith("Dolby Vision"): + if hdr_format_full.startswith("Dolby Vision"): name += " DV" - if DYNAMIC_RANGE_MAP.get(hdr_format) and DYNAMIC_RANGE_MAP.get(hdr_format) != "DV": + if any(indicator in hdr_format_full for indicator in ["HDR10", "SMPTE ST 2086"]): name += " HDR" else: name += f" {DYNAMIC_RANGE_MAP.get(hdr_format)} " - elif trc and "HLG" in trc: + elif "HLG" in trc or "Hybrid Log-Gamma" in trc or "ARIB STD-B67" in trc or "arib-std-b67" in trc.lower(): name += " HLG" + elif any(indicator in trc for indicator in ["PQ", "SMPTE ST 2084", "BT.2100"]) or "smpte2084" in trc.lower() or "bt.2020-10" in trc.lower(): + name += " HDR" if frame_rate > 30: name += " HFR" name += f" {VIDEO_CODEC_MAP.get(codec, codec)}"