A quoted name that runs on into a title; .xNNN/.zNNN volumes
"lois 1258 Billy Joel - Extremes.part01.rar lois 1258 Billy Joel - Extremes ",
"GrooveCoverage.part26.rarGrooveCoveragebestof", "Goga Sekulic.part134.rar -
Goga Sekulic - …": the stem kept the title, and each part was a release of its
own (lois, CPP, DieViper, Maveri, tigra: ~2,400 files). runOn cuts the name
after its archive extension when a space, a dash or the name's own start
follows. And three-digit .x/.z volumes ("Reply 987986177631730.x004"),
not .x264/.x265.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
1c8da1dd12
commit
0c5ede99dd
4 files changed
+89
-12
No files matched your search
+54
-8
@@ -71,16 +71,24 @@ pub fn file_stem_re(name: &str) -> String {
|
||||
|
||||
/// Old-style rar volumes after .r99 and split zip volumes, as the file's own extension, lower case; .xNN but not
|
||||
/// .x32/.x64/.x86 (no lookahead here: the builds are put back by old_volume_at).
|
||||
static OLD_RAR_VOLUME: LazyLock<Regex> = LazyLock::new(|| re(r"\.(?:[s-vxz])[0-9]{2}$"));
|
||||
static OLD_RAR_VOLUME: LazyLock<Regex> = LazyLock::new(|| re(r"\.(?:[s-v][0-9]{2}|[xz][0-9]{2,3})$"));
|
||||
|
||||
/// Whether a name ends with an old rar or split zip volume (OLD_RAR_VOLUME without the .x builds).
|
||||
fn old_volume_at(b: &[u8]) -> bool {
|
||||
let len = b.len();
|
||||
len >= 4
|
||||
&& b[len - 4] == b'.'
|
||||
&& matches!(b[len - 3], b's'..=b'v' | b'x' | b'z')
|
||||
&& b[len - 2..].iter().all(u8::is_ascii_digit)
|
||||
&& !(b[len - 3] == b'x' && matches!(&b[len - 2..], b"32" | b"64" | b"86"))
|
||||
let digits = b.iter().rev().take_while(|c| c.is_ascii_digit()).count();
|
||||
if !(2..=3).contains(&digits) || len < digits + 2 || b[len - digits - 2] != b'.' {
|
||||
return false;
|
||||
}
|
||||
let letter = b[len - digits - 1];
|
||||
let number = &b[len - digits..];
|
||||
match letter {
|
||||
b's'..=b'v' => digits == 2,
|
||||
b'z' => true,
|
||||
// Not the builds .x32, .x64, .x86, .x264, .x265.
|
||||
b'x' => !matches!(number, b"32" | b"64" | b"86" | b"264" | b"265"),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
static QUOTED: LazyLock<Regex> = LazyLock::new(|| re(r#""[^"]*""#));
|
||||
static COUNTERS: LazyLock<Regex> = LazyLock::new(|| re(r"\[[0-9]+/[0-9]+\]|\([0-9]+/[0-9]+\)"));
|
||||
@@ -229,7 +237,7 @@ pub fn file_stem(name: &str) -> String {
|
||||
let mut len = b.len();
|
||||
// Old-style rar volumes after .r99 (".s41"), as the file's own extension, lower case.
|
||||
if old_volume_at(b) {
|
||||
len -= 4;
|
||||
len -= b.iter().rev().take_while(|c| c.is_ascii_digit()).count() + 2;
|
||||
}
|
||||
let mut changed = true;
|
||||
while changed {
|
||||
@@ -679,6 +687,27 @@ pub fn random_poster(from: &str) -> bool {
|
||||
looks_random(&local)
|
||||
}
|
||||
|
||||
/// RUN_ON (lib/release/identity.ts): an archive's or par2's extension.
|
||||
static RUN_ON: LazyLock<Regex> = LazyLock::new(|| re(r"(?i)\.(?:part[0-9]+\.rar|vol[0-9]+[+-][0-9]+\.par2|par2|rar|r[0-9]{2,3}|7z(?:\.[0-9]{3})?|zip|nzb|nfo|sfv)"));
|
||||
|
||||
/// runOn (lib/release/identity.ts): a quoted name that runs on past its extension into a title, cut there.
|
||||
pub fn run_on(name: &str) -> &str {
|
||||
let b = name.as_bytes();
|
||||
let ascii = b.len() >= 4 && b[..4].is_ascii();
|
||||
for m in RUN_ON.find_iter(b) {
|
||||
let rest = &name[m.end()..];
|
||||
if rest.is_empty() {
|
||||
return name;
|
||||
}
|
||||
let spaced = rest.starts_with(js::is_space) || rest.trim_start_matches(js::is_space).starts_with('-');
|
||||
let repeats = ascii && rest.len() >= 4 && rest.as_bytes()[..4].eq_ignore_ascii_case(&b[..4]);
|
||||
if spaced || repeats {
|
||||
return &name[..m.end()];
|
||||
}
|
||||
}
|
||||
name
|
||||
}
|
||||
|
||||
/// sizeAfterName (lib/release/identity.ts): the subject without a number after the file's unquoted name at its end.
|
||||
pub fn size_after_name(subject: &str, name: &str) -> String {
|
||||
let end = subject.trim_end_matches(js::is_space);
|
||||
@@ -703,7 +732,7 @@ pub fn release_identity(poster: &str, subject: &str, name: &str) -> Release {
|
||||
let poster = if random_poster(poster) { "" } else { poster };
|
||||
// The post rule's key takes the [i/M] total; the release's file total any counter's (counterTotal).
|
||||
let post_total = file_counter_total(subject);
|
||||
let stem = file_stem(name);
|
||||
let stem = file_stem(run_on(name));
|
||||
// A name that isn't quoted (unquoted_name) is taken out as the quotes would have been.
|
||||
// The subject here has its spaces collapsed; the name may not.
|
||||
// Other quoted text stays: it names the release (">>> CREATIVE COMMONS NZB <<< "0190 alarm 5.0 " - File 1 of 9: …").
|
||||
@@ -1445,6 +1474,8 @@ mod image_set_tests {
|
||||
("App.x86", "App.x86"),
|
||||
("Licence 700790900887990.z18", "Licence 700790900887990"),
|
||||
("Licence 077887994400668.x12", "Licence 077887994400668"),
|
||||
("Reply 987986177631730.x004", "Reply 987986177631730"),
|
||||
("Some.Movie.2010.x264", "Some.Movie.2010.x264"),
|
||||
("chappelle1.part02.rev", "chappelle1"),
|
||||
("chappelle1.rev", "chappelle1"),
|
||||
("VwE3i90MVX9dqMFuDfzdS7Q6.part1.par2", "VwE3i90MVX9dqMFuDfzdS7Q6"),
|
||||
@@ -1459,6 +1490,21 @@ mod image_set_tests {
|
||||
assert_eq!(super::size_after_name("(Hot MILF getting banged hard)[27/70] - 2407.jpg - 28", "2407.jpg"), "(Hot MILF getting banged hard)[27/70] - 2407.jpg");
|
||||
assert_eq!(super::size_after_name(r#"Show [01/10] - "a.jpg" - 28"#, "a.jpg"), r#"Show [01/10] - "a.jpg" - 28"#);
|
||||
assert_eq!(super::size_after_name("Show - Episode 05", "x.mkv"), "Show - Episode 05");
|
||||
for (n, cut) in [
|
||||
("lois 1258 Billy Joel - Extremes.part01.rar lois 1258 Billy Joel - Extremes ", "lois 1258 Billy Joel - Extremes.part01.rar"),
|
||||
("GrooveCoverage.part26.rarGrooveCoveragebestof", "GrooveCoverage.part26.rar"),
|
||||
("Goga Sekulic.part134.rar - Goga Sekulic - Diskografija (2000-2014).", "Goga Sekulic.part134.rar"),
|
||||
("HASf293jLAIWUELvhaG3.part091.rar HASf293jLAIWUELvhaG3", "HASf293jLAIWUELvhaG3.part091.rar"),
|
||||
("Movie.rar.Collection.mkv", "Movie.rar.Collection.mkv"),
|
||||
("x.part01.rar", "x.part01.rar"),
|
||||
] {
|
||||
assert_eq!(super::run_on(n), cut, "{n}");
|
||||
}
|
||||
let lois = |i: &str, n: &str| super::release_identity("p", &format!(r#"(thnx to original poster) [{i}/92] - "{n}" yEnc"#), n);
|
||||
assert_eq!(
|
||||
lois("02", "lois 1258 Billy Joel - Extremes.part01.rar lois 1258 Billy Joel - Extremes ").key,
|
||||
lois("01", "lois 1258 Billy Joel - Extremes.par2 lois 1258 Billy Joel - Extremes ").key
|
||||
);
|
||||
let milf = |i: &str, n: &str, kb: &str| super::release_identity("p", &format!("(Hot MILF getting banged hard)[{i}/70] - {n} - {kb}"), n);
|
||||
assert_eq!(milf("27", "2407.jpg", "28").key, milf("28", "2408.jpg", "31").key);
|
||||
assert_eq!(super::file_stem_re("rld-gtre.r13.002"), "rld-gtre");
|
||||
|
||||
Reference in new issue
Block a user