fix(overlays): derive dynamic-range badges from Dolby Vision metadata (#365)

* fix(overlays): derive dynamic-range badges from Dolby Vision metadata

Dolby Vision files were labeled with a generic "HDR" badge everywhere
outside the Media Info dialog, because badge sites only consulted the
bare FileVersion.hdr boolean even though the payload carries
video_tracks[].dolby_vision / dv_profile / video_range_type /
color_transfer.

Web: add a shared helper (web/src/lib/videoRange.ts) that derives a
display label ("DV", "DV HDR10", "DV HLG", "HDR10+", "HDR10", "HLG")
from the probed video tracks, mirroring the server-side normalizeHDR
vocabulary, with the hdr boolean kept as the last-resort fallback for
stale pre-DV probe rows. Use it in QualityBadges, VersionDropdown,
VersionFlyout, and the player HUD (playback-info) in place of the
hardcoded "HDR" literal. Badge styling is unchanged.

Server: in internal/overlays/summary.go, break bestFile resolution
ties by richness of dynamic-range metadata (DV > explicit HDR10/HLG
via color_transfer > bare hdr boolean > SDR) so a first-scanned
generic-HDR file no longer masks a Dolby Vision sibling on card
overlays. Full ties still keep the earliest file, so the selection
stays deterministic.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(overlays): detect Dolby Vision via dv_profile and DOVI range type

Probed rows set DolbyVision and DVProfile together, but catalog-seeded
or imported tracks can carry only dv_profile or a DOVI* video_range_type
with an empty dolby_vision string. Share one hasDolbyVision predicate
between rangeRank and normalizeHDR so those rows rank and label as DV,
matching the web videoRange helper.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(overlays): read video_range_type and hdr10_plus in hdrTypeFromTracks

Review follow-up: hdrTypeFromTracks only inspected color_transfer, so
server card overlays could never label HDR10+ and a track whose only
signal is video_range_type (e.g. catalog-seeded rows without probed
color metadata) fell through to the bare-boolean tier of rangeRank —
inconsistent with hasDolbyVision, which already reads the range type.
The server now shares the web helper's detection order exactly, making
the web/server vocabulary mirror claim true.

Also drops the unused video_range field from the web VideoRangeTrack
interface.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: rxwatcher <rxwatcher@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Quick104 <31828688+Quick104@users.noreply.github.com>
This commit is contained in:
RXWatcher
2026-07-16 10:53:30 -04:00
committed by GitHub
co-authored by rxwatcher Claude Opus 4.8 Quick104
parent f377be9d6e
commit 0f9584ef42
9 changed files with 419 additions and 22 deletions
+3 -1
View File
@@ -170,7 +170,9 @@ describe("playback info helpers", () => {
runtimeStats: {},
});
expect(rowValue(sections, "Player", "Auto-switched from")).toBe("2160p HEVC HDR");
// The default fixture is a Dolby Vision (Profile 8.1) file, so the range
// badge reads "DV" instead of the old generic boolean-derived "HDR".
expect(rowValue(sections, "Player", "Auto-switched from")).toBe("2160p HEVC DV");
expect(rowValue(sections, "Current Source File", "Video codec")).toBe("H.264 High");
});
+3 -5
View File
@@ -6,6 +6,7 @@ import {
formatMbpsFromKbps,
formatSampleRate,
} from "@/lib/mediaFormat";
import { videoRangeLabel } from "@/lib/videoRange";
import type {
PlaybackSessionPlaybackInfo,
PlayMethod,
@@ -223,7 +224,7 @@ function formatRequestedSourceVersion(version: PlayerFileVersion): string {
const parts = [
version.resolution?.trim(),
formatCodecLabel(version.codec_video),
version.hdr ? "HDR" : null,
videoRangeLabel(version) || null,
].filter(Boolean);
return parts.join(" ");
}
@@ -333,11 +334,8 @@ export function formatVideoRangeType(
if (track?.video_range) {
return track.video_range;
}
if (version?.hdr) {
return "HDR";
}
if (version) {
return "SDR";
return videoRangeLabel(version) || "SDR";
}
return "—";
}