fix(parse): pack titles and degenerate ranges
COMPLETE before the season tag was weak junk, so it stayed in the title and exact-title matching failed silently (#135). It now closes the boundary wherever it lands. S01-S01 produced no claim because the dash-range branch required last > season; a degenerate range is one season's pack, matching the rule match_episode lifted.
This commit is contained in:
@@ -621,6 +621,10 @@ mod tests {
|
||||
"Fallout.S01.1080p.BluRay.x264-GROUP",
|
||||
MatchShape::SeasonPack,
|
||||
),
|
||||
(
|
||||
"Fallout.S01-S01.1080p.BluRay.x264-GROUP",
|
||||
MatchShape::SeasonPack,
|
||||
),
|
||||
];
|
||||
for (name, shape) in cases {
|
||||
assert_eq!(
|
||||
@@ -639,6 +643,32 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
/// `COMPLETE` before the season tag used to stay in the title and
|
||||
/// break the exact-title comparison (#135).
|
||||
#[test]
|
||||
fn a_pack_marker_before_the_tag_still_matches() {
|
||||
let wanted = WantedEpisode {
|
||||
id: EpisodeId(10),
|
||||
tmdb_id: None,
|
||||
imdb_id: None,
|
||||
title: "Bluey".to_owned(),
|
||||
season: 1,
|
||||
episode: 3,
|
||||
};
|
||||
assert_eq!(
|
||||
match_episode(
|
||||
&wanted,
|
||||
&ReleaseIds::default(),
|
||||
&arr_parse::parse("Bluey.COMPLETE.S01.1080p.WEB-DL-GROUP"),
|
||||
),
|
||||
Some(EpisodeMatch {
|
||||
episode: EpisodeId(10),
|
||||
kind: MatchKind::TitleAndYear,
|
||||
shape: MatchShape::SeasonPack,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/// Punctuation, case and accents in the series title do not block the
|
||||
/// match.
|
||||
#[test]
|
||||
@@ -808,9 +838,7 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
/// `S01-S01` does not parse as a claim (`arr-parse` takes only a real
|
||||
/// range), but the lifted rule is what a degenerate range would mean:
|
||||
/// one season's pack, not a multi-season one.
|
||||
/// A degenerate range means one season's pack, not a multi-season one.
|
||||
#[test]
|
||||
fn a_degenerate_season_range_is_this_seasons_pack() {
|
||||
use super::{is_single_episode, is_this_seasons_pack};
|
||||
|
||||
@@ -36,7 +36,7 @@ pub(crate) fn tag_of(token: &str) -> Option<EpisodeClaim> {
|
||||
.or_else(|| date_tag(token))
|
||||
}
|
||||
|
||||
/// `S01`, `S01-S03`, `S01E02`, `S01E02E03`, `S01E02-E04`.
|
||||
/// `S01`, `S01-S03`, `S01-S01`, `S01E02`, `S01E02E03`, `S01E02-E04`.
|
||||
fn season_tag(token: &str) -> Option<EpisodeClaim> {
|
||||
let rest = token.strip_prefix('s')?;
|
||||
let (season, mut rest) = digits(rest);
|
||||
@@ -55,7 +55,8 @@ fn season_tag(token: &str) -> Option<EpisodeClaim> {
|
||||
return None;
|
||||
}
|
||||
let last: u32 = last.parse().ok()?;
|
||||
return (last > season).then_some(EpisodeClaim::Seasons {
|
||||
// A degenerate range (`S01-S01`) is one season's pack, not nothing.
|
||||
return (last >= season).then_some(EpisodeClaim::Seasons {
|
||||
first: season,
|
||||
last,
|
||||
});
|
||||
@@ -148,7 +149,7 @@ fn season_words(token: &str) -> Option<EpisodeClaim> {
|
||||
return None;
|
||||
}
|
||||
let last: u32 = last.parse().ok()?;
|
||||
(last > first).then_some(EpisodeClaim::Seasons { first, last })
|
||||
(last >= first).then_some(EpisodeClaim::Seasons { first, last })
|
||||
}
|
||||
|
||||
/// Splits a leading run of ASCII digits off a token.
|
||||
|
||||
@@ -135,9 +135,9 @@ fn classify_exact(t: &str) -> Option<(Marker, Strength)> {
|
||||
// "Legendado" claims pt-BR *subtitles* over original audio — it must
|
||||
// NOT become a PtBr audio claim or main-root originals get rejected.
|
||||
"proper" | "repack" | "internal" | "hybrid" | "10bit" | "8bit" | "hi10p" | "amzn"
|
||||
| "dsnp" | "atvp" | "hmax" | "pcok" | "legendado" => (Marker::Junk, Strong),
|
||||
"nf" | "hulu" | "max" | "itunes" | "cr" | "complete" | "sample" | "subbed" | "subs"
|
||||
| "sub" | "mkv" | "mp4" | "avi" | "www" | "com" | "net" | "org" | "retail" | "readnfo" => {
|
||||
| "dsnp" | "atvp" | "hmax" | "pcok" | "legendado" | "complete" => (Marker::Junk, Strong),
|
||||
"nf" | "hulu" | "max" | "itunes" | "cr" | "sample" | "subbed" | "subs" | "sub" | "mkv"
|
||||
| "mp4" | "avi" | "www" | "com" | "net" | "org" | "retail" | "readnfo" => {
|
||||
(Marker::Junk, Weak)
|
||||
}
|
||||
_ => return None,
|
||||
|
||||
@@ -307,6 +307,42 @@ fn cases() -> Vec<Case> {
|
||||
..NameClaims::default()
|
||||
},
|
||||
},
|
||||
Case {
|
||||
// `COMPLETE` before the tag closes the title like any strong
|
||||
// marker, wherever the group puts it.
|
||||
name: "Bluey.COMPLETE.S01.1080p.WEB-DL",
|
||||
want: NameClaims {
|
||||
title: s("Bluey"),
|
||||
resolution: Some(Resolution::P1080),
|
||||
source: Some(Source::WebDl),
|
||||
episode: Some(EpisodeClaim::Season { season: 1 }),
|
||||
..NameClaims::default()
|
||||
},
|
||||
},
|
||||
Case {
|
||||
// The trailing placement already worked; it keeps working.
|
||||
name: "Bluey.S01.COMPLETE.1080p.WEB-DL",
|
||||
want: NameClaims {
|
||||
title: s("Bluey"),
|
||||
resolution: Some(Resolution::P1080),
|
||||
source: Some(Source::WebDl),
|
||||
episode: Some(EpisodeClaim::Season { season: 1 }),
|
||||
..NameClaims::default()
|
||||
},
|
||||
},
|
||||
Case {
|
||||
// A degenerate range is one season's pack.
|
||||
name: "Fallout.S01-S01.1080p.BluRay.x264-GROUP",
|
||||
want: NameClaims {
|
||||
title: s("Fallout"),
|
||||
resolution: Some(Resolution::P1080),
|
||||
source: Some(Source::BluRay),
|
||||
codec: Some(Codec::X264),
|
||||
group: s("GROUP"),
|
||||
episode: Some(EpisodeClaim::Seasons { first: 1, last: 1 }),
|
||||
..NameClaims::default()
|
||||
},
|
||||
},
|
||||
Case {
|
||||
name: "Movie.2019.4K.HDR.DV.2160p.BDRemux.Ita.Eng.x265-NAHOM",
|
||||
want: NameClaims {
|
||||
|
||||
Reference in New Issue
Block a user