Enforce Dolby Vision profile policy (#61)
ci / rust (push) Successful in 58s
ci / web (push) Successful in 8s
e2e / e2e (push) Successful in 1m23s

This commit was merged in pull request #61.
This commit is contained in:
2026-08-22 20:52:06 +01:00
parent 99ac79373d
commit c7cb3652e5
+126 -6
View File
@@ -2,8 +2,8 @@ use arr_parse::{LanguageMarker, NameClaims};
use crate::{
lang::{is_resolved_portuguese, language_of_marker},
Language, MovieOverrides, Policy, ProbedMedia, RequiredAudio, Resolution, Rule, Source,
Verdict,
HdrFormat, Language, MovieOverrides, Policy, ProbedMedia, RequiredAudio, Resolution, Rule,
Source, Verdict,
};
/// The evidence available while evaluating a candidate.
@@ -105,9 +105,10 @@ pub fn evaluate(
original_language,
candidate,
};
let rules: [&dyn PolicyRule; 4] = [
let rules: [&dyn PolicyRule; 5] = [
&ResolutionRule,
&SourceRule,
&HdrRule,
&DubBlacklistRule,
&RequiredAudioRule,
];
@@ -200,6 +201,38 @@ impl PolicyRule for SourceRule {
}
}
/// Applies Dolby Vision profile policy using post-download probe evidence.
#[derive(Clone, Copy, Debug, Default)]
pub struct HdrRule;
impl PolicyRule for HdrRule {
fn evaluate(&self, context: &EvaluationContext<'_>) -> RuleEvaluation {
let Candidate::PostDownload(media) = context.candidate else {
return RuleEvaluation::Unknown(RuleKind::DolbyVisionProfile);
};
let HdrFormat::DolbyVision(profile) = media.hdr else {
return RuleEvaluation::Pass(RuleKind::DolbyVisionProfile);
};
let rejected = context
.policy
.hdr_rules
.rejected_dolby_vision_profiles
.iter()
.any(|blocked| {
blocked.profile == profile.profile
&& blocked.compatibility_id.is_none_or(|compatibility_id| {
profile.compatibility_id == Some(compatibility_id)
})
});
if rejected {
RuleEvaluation::HardFail(Rule::DolbyVisionProfile(profile))
} else {
RuleEvaluation::Pass(RuleKind::DolbyVisionProfile)
}
}
}
/// The one language expression from `DESIGN.md` §5.2:
///
/// ```text
@@ -363,7 +396,9 @@ mod tests {
use arr_parse::{NameClaims, Resolution as ClaimedResolution, Source as ClaimedSource};
use super::*;
use crate::{AudioTrack, HdrFormat, HdrRules, PolicyId, RequiredAudio, SubtitleTrack};
use crate::{
AudioTrack, DolbyVisionProfile, HdrFormat, HdrRules, PolicyId, RequiredAudio, SubtitleTrack,
};
fn en() -> Language {
Language::Other("en".to_owned())
@@ -378,7 +413,16 @@ mod tests {
required_audio: RequiredAudio::OriginalLanguage,
dub_blacklist: vec![Language::PortugueseBrazil],
hdr_rules: HdrRules {
rejected_dolby_vision_profiles: Vec::new(),
rejected_dolby_vision_profiles: vec![
DolbyVisionProfile {
profile: 5,
compatibility_id: None,
},
DolbyVisionProfile {
profile: 7,
compatibility_id: None,
},
],
},
size_bands: BTreeMap::new(),
resolution_preference: vec![Resolution::R2160p, Resolution::R1080p],
@@ -470,6 +514,7 @@ mod tests {
vec![
RuleEvaluation::Unknown(RuleKind::Resolution),
RuleEvaluation::Unknown(RuleKind::Source),
RuleEvaluation::Unknown(RuleKind::DolbyVisionProfile),
RuleEvaluation::Unknown(RuleKind::DubBlacklist),
RuleEvaluation::Unknown(RuleKind::RequiredAudio),
]
@@ -648,6 +693,81 @@ mod tests {
}
}
#[test]
fn dolby_vision_profile_5_is_rejected() {
assert_dolby_vision_verdict(&policy(), 5, None, true);
}
#[test]
fn dolby_vision_profile_7_is_rejected() {
assert_dolby_vision_verdict(&policy(), 7, Some(6), true);
}
#[test]
fn dolby_vision_profile_8_1_is_accepted() {
assert_dolby_vision_verdict(&policy(), 8, Some(1), false);
}
#[test]
fn compatibility_specific_rule_matches_only_that_id() {
let mut policy = policy();
policy
.hdr_rules
.rejected_dolby_vision_profiles
.push(DolbyVisionProfile {
profile: 8,
compatibility_id: Some(2),
});
assert_dolby_vision_verdict(&policy, 8, Some(2), true);
assert_dolby_vision_verdict(&policy, 8, Some(1), false);
}
fn assert_dolby_vision_verdict(
policy: &Policy,
profile: u8,
compatibility_id: Option<u8>,
rejected: bool,
) {
let mut media = probed(Resolution::R2160p, Some(Source::WebDl));
let profile = DolbyVisionProfile {
profile,
compatibility_id,
};
media.hdr = HdrFormat::DolbyVision(profile);
let report = evaluate(
policy,
&MovieOverrides::default(),
&en(),
Candidate::PostDownload(&media),
);
let expected = if rejected {
Verdict::Rejected(Rule::DolbyVisionProfile(profile))
} else {
Verdict::Eligible
};
assert_eq!(report.verdict, expected);
}
#[test]
fn pre_grab_dolby_vision_claim_stays_unknown() {
let claims = arr_parse::parse("Movie.2024.2160p.WEB-DL.DV-GROUP");
let report = evaluate(
&policy(),
&MovieOverrides::default(),
&en(),
Candidate::PreGrab(&claims),
);
assert_eq!(report.verdict, Verdict::Eligible);
assert_eq!(
report.rules[2],
RuleEvaluation::Unknown(RuleKind::DolbyVisionProfile)
);
}
#[derive(Debug)]
struct FixedRule {
evaluation: RuleEvaluation,
@@ -929,7 +1049,7 @@ mod tests {
);
assert_eq!(report.verdict, Verdict::Eligible);
assert_eq!(
report.rules[3],
report.rules[4],
RuleEvaluation::Unknown(RuleKind::RequiredAudio)
);
}