Enforce Dolby Vision profile policy (#61)
This commit was merged in pull request #61.
This commit is contained in:
@@ -2,8 +2,8 @@ use arr_parse::{LanguageMarker, NameClaims};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
lang::{is_resolved_portuguese, language_of_marker},
|
lang::{is_resolved_portuguese, language_of_marker},
|
||||||
Language, MovieOverrides, Policy, ProbedMedia, RequiredAudio, Resolution, Rule, Source,
|
HdrFormat, Language, MovieOverrides, Policy, ProbedMedia, RequiredAudio, Resolution, Rule,
|
||||||
Verdict,
|
Source, Verdict,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The evidence available while evaluating a candidate.
|
/// The evidence available while evaluating a candidate.
|
||||||
@@ -105,9 +105,10 @@ pub fn evaluate(
|
|||||||
original_language,
|
original_language,
|
||||||
candidate,
|
candidate,
|
||||||
};
|
};
|
||||||
let rules: [&dyn PolicyRule; 4] = [
|
let rules: [&dyn PolicyRule; 5] = [
|
||||||
&ResolutionRule,
|
&ResolutionRule,
|
||||||
&SourceRule,
|
&SourceRule,
|
||||||
|
&HdrRule,
|
||||||
&DubBlacklistRule,
|
&DubBlacklistRule,
|
||||||
&RequiredAudioRule,
|
&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:
|
/// The one language expression from `DESIGN.md` §5.2:
|
||||||
///
|
///
|
||||||
/// ```text
|
/// ```text
|
||||||
@@ -363,7 +396,9 @@ mod tests {
|
|||||||
use arr_parse::{NameClaims, Resolution as ClaimedResolution, Source as ClaimedSource};
|
use arr_parse::{NameClaims, Resolution as ClaimedResolution, Source as ClaimedSource};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{AudioTrack, HdrFormat, HdrRules, PolicyId, RequiredAudio, SubtitleTrack};
|
use crate::{
|
||||||
|
AudioTrack, DolbyVisionProfile, HdrFormat, HdrRules, PolicyId, RequiredAudio, SubtitleTrack,
|
||||||
|
};
|
||||||
|
|
||||||
fn en() -> Language {
|
fn en() -> Language {
|
||||||
Language::Other("en".to_owned())
|
Language::Other("en".to_owned())
|
||||||
@@ -378,7 +413,16 @@ mod tests {
|
|||||||
required_audio: RequiredAudio::OriginalLanguage,
|
required_audio: RequiredAudio::OriginalLanguage,
|
||||||
dub_blacklist: vec![Language::PortugueseBrazil],
|
dub_blacklist: vec![Language::PortugueseBrazil],
|
||||||
hdr_rules: HdrRules {
|
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(),
|
size_bands: BTreeMap::new(),
|
||||||
resolution_preference: vec![Resolution::R2160p, Resolution::R1080p],
|
resolution_preference: vec![Resolution::R2160p, Resolution::R1080p],
|
||||||
@@ -470,6 +514,7 @@ mod tests {
|
|||||||
vec![
|
vec![
|
||||||
RuleEvaluation::Unknown(RuleKind::Resolution),
|
RuleEvaluation::Unknown(RuleKind::Resolution),
|
||||||
RuleEvaluation::Unknown(RuleKind::Source),
|
RuleEvaluation::Unknown(RuleKind::Source),
|
||||||
|
RuleEvaluation::Unknown(RuleKind::DolbyVisionProfile),
|
||||||
RuleEvaluation::Unknown(RuleKind::DubBlacklist),
|
RuleEvaluation::Unknown(RuleKind::DubBlacklist),
|
||||||
RuleEvaluation::Unknown(RuleKind::RequiredAudio),
|
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)]
|
#[derive(Debug)]
|
||||||
struct FixedRule {
|
struct FixedRule {
|
||||||
evaluation: RuleEvaluation,
|
evaluation: RuleEvaluation,
|
||||||
@@ -929,7 +1049,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
assert_eq!(report.verdict, Verdict::Eligible);
|
assert_eq!(report.verdict, Verdict::Eligible);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
report.rules[3],
|
report.rules[4],
|
||||||
RuleEvaluation::Unknown(RuleKind::RequiredAudio)
|
RuleEvaluation::Unknown(RuleKind::RequiredAudio)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user