From 3fd08b598ac97cf38ddb46a5e622b3642ec134b4 Mon Sep 17 00:00:00 2001 From: Daan Meijer Date: Tue, 13 Oct 2026 10:33:52 +0200 Subject: [PATCH] An image's post token needs a word in it, not only a size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "01of37 ## Alexi uses strange toys … ## alexis001.jpg (1/1) 57295b": with the whole text as the name, the remainder is the file's size "57295b", which 229189f took for a post token: 16 sets of 36-37 images became 268 releases. "MDG005b" has letters in a row; "57295b" doesn't. Co-Authored-By: Claude Opus 5.5 --- edge/src/names.rs | 10 +++++++++- lib/release/identity.ts | 4 +++- tests/unit/release/identity.spec.ts | 7 +++++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/edge/src/names.rs b/edge/src/names.rs index c70b21a..4aa244b 100644 --- a/edge/src/names.rs +++ b/edge/src/names.rs @@ -845,7 +845,9 @@ pub fn release_identity(poster: &str, subject: &str, name: &str) -> Release { let set = image_set(&stem); let set = if set.is_empty() { name.clone() } else { set }; // Under a post token ("MDG005b - (01/90) "IMG_2307.JPG""): the post's too. - let key = if is_post_token(&remainder) { hash(&["stem", poster, &set, &remainder]) } else { hash(&["stem", poster, &set]) }; + // A word in it, not a size ("… alexis001.jpg 57295b"). + let post = is_post_token(&remainder) && remainder.as_bytes().windows(2).any(|w| w[0].is_ascii_alphabetic() && w[1].is_ascii_alphabetic()); + let key = if post { hash(&["stem", poster, &set, &remainder]) } else { hash(&["stem", poster, &set]) }; return Release { key, name, source: "stem", file_total }; } // An audiobook's or album's tracks without a name around them: by their name without its numbers. @@ -1542,6 +1544,12 @@ mod image_set_tests { let mdg = |post: &str, i: &str, n: &str| super::release_identity("p", &format!(r#"{post} - ({i}/90) "{n}" - 16,14 MB - yEnc"#), n); assert_eq!(mdg("MDG005b", "01", "IMG_2307.JPG").key, mdg("MDG005b", "02", "IMG_2308.jpg").key); assert_ne!(mdg("MDG005b", "01", "IMG_2307.JPG").key, mdg("MDG006a", "01", "IMG_4410.JPG").key); + // The whole text before "(1/1)" is the name; the size follows the segment counter. + let alexi = |i: &str, size: &str| { + let n = format!("{i}of37 ## Alexi uses strange toys to make herself come ## alexis0{i}.jpg"); + super::release_identity("p", &format!("{n} {size}"), &n) + }; + assert_eq!(alexi("01", "57295b").key, alexi("02", "32202b").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"); diff --git a/lib/release/identity.ts b/lib/release/identity.ts index 73f9c9c..2eb76d8 100644 --- a/lib/release/identity.ts +++ b/lib/release/identity.ts @@ -435,7 +435,9 @@ export function releaseIdentity(input: ReleaseInput): ReleaseIdentity | null { // every set named "IMG" was one (609 images for 90; LOG.md 2026-10-13 (42)). if (image) { const set = imageSet(stem) || prefix || stem - return { key: isPostToken(remainder) ? hash('stem', poster, set, remainder) : hash('stem', poster, set), name: prefix || stem, fileTotal, source: 'stem' } + // A word in it, not a size ("01of37 ## Alexi … ## alexis001.jpg 57295b": each image was a release of its own). + const post = isPostToken(remainder) && /[A-Za-z]{2}/.test(remainder) + return { key: post ? hash('stem', poster, set, remainder) : hash('stem', poster, set), name: prefix || stem, fileTotal, source: 'stem' } } // An audiobook's or album's tracks without a name around them: by their name without its numbers, as an // image set ("… Seeing A Large Cat - D11.16-22.mp3", "Candy Dulfer - Candy Store - 11 - everytime.mp3"). diff --git a/tests/unit/release/identity.spec.ts b/tests/unit/release/identity.spec.ts index d062f9e..bf34a11 100644 --- a/tests/unit/release/identity.spec.ts +++ b/tests/unit/release/identity.spec.ts @@ -419,6 +419,13 @@ test.group('release / par2 names', () => { const mdg = (post: string, i: string, n: string) => id(`${post} - (${i}/90) "${n}" - 16,14 MB - yEnc`, n) assert.equal(mdg('MDG005b', '01', 'IMG_2307.JPG').key, mdg('MDG005b', '02', 'IMG_2308.jpg').key) assert.notEqual(mdg('MDG005b', '01', 'IMG_2307.JPG').key, mdg('MDG006a', '01', 'IMG_4410.JPG').key) + // A size isn't a post token. + // The whole text before "(1/1)" is the name; the size follows the segment counter. + const alexi = (i: string, size: string) => { + const n = `${i}of37 ## Alexi uses strange toys to make herself come ## alexis0${i}.jpg` + return id(`${n} ${size}`, n) + } + assert.equal(alexi('01', '57295b').key, alexi('02', '32202b').key) }) test('an image without words around it is keyed by its set', ({ assert }) => {