Split zip volumes (.zNN) and .xNN as volumes, but not .x32/.x64/.x86
87e15d8's .[s-v]NN let "Licence 700790900887990.z18" and "….x31" uploads fall apart again (+1,740 releases on the corpus). .zNN is a split zip volume; .xNN is a volume unless it's a build. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
87e15d810d
commit
8d5385fdec
3 files changed
+25
-6
No files matched your search
+19
-4
@@ -50,7 +50,8 @@ static SUFFIXES: LazyLock<Vec<(Regex, &'static str)>> = LazyLock::new(|| {
|
||||
/// fileStem with the regexes, as in the TypeScript (the reference for file_stem's tests).
|
||||
#[allow(dead_code)]
|
||||
pub fn file_stem_re(name: &str) -> String {
|
||||
let mut stem = replace(&OLD_RAR_VOLUME, js::trim(name), "", false);
|
||||
let trimmed = js::trim(name);
|
||||
let mut stem = if old_volume_at(trimmed.as_bytes()) { replace(&OLD_RAR_VOLUME, trimmed, "", false) } else { trimmed.to_string() };
|
||||
let mut changed = true;
|
||||
while changed {
|
||||
changed = false;
|
||||
@@ -68,8 +69,19 @@ pub fn file_stem_re(name: &str) -> String {
|
||||
stem
|
||||
}
|
||||
|
||||
/// Old-style rar volumes after .r99, as the file's own extension, lower case, not x or z (".x64"): /\.[s-v]\d{2}$/.
|
||||
static OLD_RAR_VOLUME: LazyLock<Regex> = LazyLock::new(|| re(r"\.[s-v][0-9]{2}$"));
|
||||
/// 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}$"));
|
||||
|
||||
/// 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"))
|
||||
}
|
||||
static QUOTED: LazyLock<Regex> = LazyLock::new(|| re(r#""[^"]*""#));
|
||||
static COUNTERS: LazyLock<Regex> = LazyLock::new(|| re(r"\[[0-9]+/[0-9]+\]|\([0-9]+/[0-9]+\)"));
|
||||
static YENC_END: LazyLock<Regex> = LazyLock::new(|| re(r"(?i)\byEnc\b(SP+[0-9]+)?SP*$"));
|
||||
@@ -216,7 +228,7 @@ pub fn file_stem(name: &str) -> String {
|
||||
let b = stem.as_bytes();
|
||||
let mut len = b.len();
|
||||
// Old-style rar volumes after .r99 (".s41"), as the file's own extension, lower case.
|
||||
if len >= 4 && b[len - 4] == b'.' && (b's'..=b'v').contains(&b[len - 3]) && b[len - 2..].iter().all(u8::is_ascii_digit) {
|
||||
if old_volume_at(b) {
|
||||
len -= 4;
|
||||
}
|
||||
let mut changed = true;
|
||||
@@ -1428,6 +1440,9 @@ mod image_set_tests {
|
||||
("the.office.us.s01.rar", "the.office.us.s01"),
|
||||
("Some.Show.S01", "Some.Show.S01"),
|
||||
("Electric.Rain.Swift.3D.PS.v1.0.142.x64", "Electric.Rain.Swift.3D.PS.v1.0.142.x64"),
|
||||
("App.x86", "App.x86"),
|
||||
("Licence 700790900887990.z18", "Licence 700790900887990"),
|
||||
("Licence 077887994400668.x12", "Licence 077887994400668"),
|
||||
("chappelle1.part02.rev", "chappelle1"),
|
||||
("chappelle1.rev", "chappelle1"),
|
||||
("VwE3i90MVX9dqMFuDfzdS7Q6.part1.par2", "VwE3i90MVX9dqMFuDfzdS7Q6"),
|
||||
|
||||
@@ -49,8 +49,9 @@ const SUFFIXES = [
|
||||
/** Strips per-file suffixes (volume numbers, archive and par2 extensions) from a filename. */
|
||||
export function fileStem(name: string): string {
|
||||
// Old-style rar volumes after .r99 ("BD_NoTHing018.s41", "….s00", ".t91", ".v81"): only as the file's own extension, in
|
||||
// lower case, so a season ("show.s01.rar", "Show.S01") stays; not x or z (".x64", ".x86" builds; ".z01" goes with .zip).
|
||||
let stem = name.trim().replace(/\.[s-v]\d{2}$/, '')
|
||||
// lower case, so a season ("show.s01.rar", "Show.S01") stays. Split zip volumes (".z18"), and .xNN but not the builds
|
||||
// ".x32", ".x64", ".x86" ("Licence 700790900887990.z18", "….x31"; "….v1.0.142.x64" stays).
|
||||
let stem = name.trim().replace(/\.(?:[s-vz]\d{2}|x(?!32$|64$|86$)\d{2})$/, '')
|
||||
let changed = true
|
||||
while (changed) {
|
||||
changed = false
|
||||
|
||||
@@ -305,6 +305,9 @@ test.group('release / par2 names', () => {
|
||||
assert.equal(fileStem('the.office.us.s01.rar'), 'the.office.us.s01')
|
||||
assert.equal(fileStem('Some.Show.S01'), 'Some.Show.S01')
|
||||
assert.equal(fileStem('Electric.Rain.Swift.3D.PS.v1.0.142.x64'), 'Electric.Rain.Swift.3D.PS.v1.0.142.x64')
|
||||
assert.equal(fileStem('App.x86'), 'App.x86')
|
||||
assert.equal(fileStem('Licence 700790900887990.z18'), 'Licence 700790900887990')
|
||||
assert.equal(fileStem('Licence 077887994400668.x12'), 'Licence 077887994400668')
|
||||
assert.equal(fileStem('chappelle1.part02.rev'), 'chappelle1')
|
||||
assert.equal(fileStem('chappelle1.rev'), 'chappelle1')
|
||||
assert.equal(fileStem('VwE3i90MVX9dqMFuDfzdS7Q6.part1.par2'), 'VwE3i90MVX9dqMFuDfzdS7Q6')
|
||||
|
||||
Reference in new issue
Block a user