fix(tracks): match probed hdr10p tracks on remote and hint dv+hdr10p on -r HDR10P

match_track treats HDR10 and HDR10P as equal in its attribute fallback. -r HDR10P warns that a DV track carries HDR10+ when one does.
This commit is contained in:
imSp4rky
2026-10-18 12:24:10 -06:00
parent 6fdfeb9cae
commit 2dd2046d65
3 changed files with 17 additions and 2 deletions
@@ -176,6 +176,14 @@ def test_match_track_by_attributes_keeps_range_and_bitrate_apart() -> None:
assert match_track(remote, [sdr, hdr]) is hdr assert match_track(remote, [sdr, hdr]) is hdr
def test_match_track_by_attributes_matches_probed_hdr10p_to_local_hdr10() -> None:
common = {"codec": "HEVC", "width": 3840, "height": 2160, "language": "en", "bitrate": 15000000}
sdr = deserialize_video({**common, "id": "a", "range": "SDR"})
hdr10 = deserialize_video({**common, "id": "b", "range": "HDR10"})
remote = deserialize_video({**common, "id": "z", "range": "HDR10P"})
assert match_track(remote, [sdr, hdr10]) is hdr10
def test_match_track_no_candidates_returns_none() -> None: def test_match_track_no_candidates_returns_none() -> None:
remote = deserialize_video({"id": "X", "codec": "AVC", "width": 1, "height": 1}) remote = deserialize_video({"id": "X", "codec": "AVC", "width": 1, "height": 1})
assert match_track(remote, []) is None assert match_track(remote, []) is None
+3
View File
@@ -2597,10 +2597,13 @@ class dl:
if keep_videos and range_: if keep_videos and range_:
# Special handling for HYBRID - don't filter, keep all HDR10 and DV tracks # Special handling for HYBRID - don't filter, keep all HDR10 and DV tracks
if Video.Range.HYBRID not in range_: if Video.Range.HYBRID not in range_:
dv_has_hdr10p = any(x.hdr10plus for x in title.tracks.videos)
title.tracks.select_video(lambda x: x.range in range_) title.tracks.select_video(lambda x: x.range in range_)
missing_ranges = [r for r in range_ if not any(x.range == r for x in title.tracks.videos)] missing_ranges = [r for r in range_ if not any(x.range == r for x in title.tracks.videos)]
for color_range in missing_ranges: for color_range in missing_ranges:
self.log.warning(f"Skipping {color_range.name} video tracks as none are available.") self.log.warning(f"Skipping {color_range.name} video tracks as none are available.")
if Video.Range.HDR10P in missing_ranges and dv_has_hdr10p:
self.log.warning("A DV track carries HDR10+: use -r DV or -r HYBRID.")
if not title.tracks.videos: if not title.tracks.videos:
self.log.error(f"There's no {', '.join(r.name for r in range_)} Video Track...") self.log.error(f"There's no {', '.join(r.name for r in range_)} Video Track...")
sys.exit(1) sys.exit(1)
+6 -2
View File
@@ -549,7 +549,11 @@ def same_bitrate(local: Optional[int], remote: Optional[int]) -> bool:
def match_track(remote_track: Track, local_tracks: list) -> Optional[Track]: def match_track(remote_track: Track, local_tracks: list) -> Optional[Track]:
"""Find the locally-parsed track that matches a remote track by ID or by attributes.""" """Find the locally-parsed track that matches a remote track by ID or by attributes.
HDR10 matches HDR10P, because the server's HDR10+ probe relabels a track that the local re-parse calls HDR10.
"""
hdr10_ranges = {Video.Range.HDR10, Video.Range.HDR10P}
remote_id = str(remote_track.id) remote_id = str(remote_track.id)
for lt in local_tracks: for lt in local_tracks:
if str(lt.id) == remote_id: if str(lt.id) == remote_id:
@@ -564,7 +568,7 @@ def match_track(remote_track: Track, local_tracks: list) -> Optional[Track]:
if ( if (
lt.width == remote_track.width lt.width == remote_track.width
and lt.height == remote_track.height and lt.height == remote_track.height
and lt.range == remote_track.range and (lt.range == remote_track.range or {lt.range, remote_track.range} == hdr10_ranges)
and same_bitrate(lt.bitrate, remote_track.bitrate) and same_bitrate(lt.bitrate, remote_track.bitrate)
): ):
return lt return lt