use crate::matcher::span::{MatchSpan, Property};
use super::super::clean::clean_title;
use super::{StrategyContext, TitleConfidence, TitleStrategy};
pub(crate) struct CjkBracket;
impl TitleStrategy for CjkBracket {
fn name(&self) -> &'static str {
"cjk_bracket"
}
fn confidence(&self) -> TitleConfidence {
TitleConfidence::Strong
}
fn try_extract(&self, ctx: &StrategyContext<'_>) -> Option<MatchSpan> {
let StrategyContext {
input,
matches,
filename_start,
} = *ctx;
let filename = &input[filename_start..];
if !filename.starts_with('[') {
return None;
}
let has_episode = matches.iter().any(|m| m.property == Property::Episode);
if !has_episode {
return None;
}
let first_close = filename.find(']')?;
let rest = &filename[first_close + 1..];
if !rest.starts_with('[') {
return None;
}
let second_open = first_close + 1;
let second_close = rest.find(']')?;
let content = &rest[1..second_close];
if content.is_empty() || content.chars().all(|c| c.is_ascii_digit()) {
return None;
}
let abs_start = filename_start + second_open + 1;
let abs_end = filename_start + second_open + 1 + content.len();
let is_claimed = matches.iter().any(|m| {
!matches!(
m.property,
Property::ReleaseGroup | Property::Title | Property::Season | Property::Episode
) && m.start < abs_end
&& m.end > abs_start
});
if is_claimed {
return None;
}
let cleaned = clean_title(content);
if cleaned.is_empty() {
return None;
}
Some(MatchSpan::new(abs_start, abs_end, Property::Title, cleaned))
}
}