From 0fafe71b21b759ee62a002db8c20d09e80744257 Mon Sep 17 00:00:00 2001 From: Daan Meijer Date: Mon, 12 Oct 2026 18:52:26 +0200 Subject: [PATCH] The poster-tag tolerance only without a counter "[ MacGyver.S01E03.DVDRip.XviD-MEDiEVAL ]-[04/38] - "sample.macgy.s01e03-med.avi"" shares one word with the sample's stem: 6225008 took the name for a tag and split the episode 17 + 21. A counted subject names its upload. Co-Authored-By: Claude Opus 5.5 --- edge/src/names.rs | 15 +++++++++------ lib/release/identity.ts | 9 +++++---- tests/unit/release/identity.spec.ts | 2 ++ 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/edge/src/names.rs b/edge/src/names.rs index 1fb6d59..d543017 100644 --- a/edge/src/names.rs +++ b/edge/src/names.rs @@ -594,7 +594,7 @@ const TAG_WORDS: [&str; 21] = [ ]; /// isPosterTag: the text outside the quotes shares no word with the file's stem. -pub fn is_poster_tag(remainder: &str, stem: &str) -> bool { +pub fn is_poster_tag(remainder: &str, stem: &str, counted: bool) -> bool { let lower = stem.to_lowercase(); let words: Vec<&str> = lower.split(|c: char| !(c.is_ascii_lowercase() || c.is_ascii_digit())).filter(|w| !w.is_empty()).collect(); let compact: String = words.concat(); @@ -621,8 +621,9 @@ pub fn is_poster_tag(remainder: &str, stem: &str) -> bool { shared += 1; } } - // A tag of 4+ words may share one with the stem ("German Board - [Usenet4ever.info] und [SecretUsenet.com]"). - shared == 0 || (shared == 1 && significant >= 4) + // Without a counter, a tag of 4+ words may share one with the stem ("German Board - [Usenet4ever.info] und [SecretUsenet.com]"). + // With one, that's a name ("[ MacGyver.S01E03.DVDRip.XviD-MEDiEVAL ]-[04/38] - "sample.macgy.s01e03-med.avi""). + shared == 0 || (shared == 1 && significant >= 4 && !counted) } /// releaseIdentity for a named (not weak) file: never null. @@ -697,7 +698,7 @@ pub fn release_identity(poster: &str, subject: &str, name: &str) -> Release { let hashed = file_total.is_none() && test(&HASHED, &stem); // A dated stem says which upload it is, short as it is ("09-30-2008_CTC.r00"). let dated = date_led(stem.as_bytes()); - let tag = hashed || (!image && !numbered && !test(&AUDIO, name) && (describes(&stem) || dated) && !looks_random(&stem) && is_poster_tag(&remainder, &stem)); + let tag = hashed || (!image && !numbered && !test(&AUDIO, name) && (describes(&stem) || dated) && !looks_random(&stem) && is_poster_tag(&remainder, &stem, total.is_some())); let prefix = if image { image_prefix(&stem) } else { String::new() }; // An image set's subject may be one word, the model's name: /^[A-Za-z]{3,}$/. let one_word = image && remainder.len() >= 3 && remainder.bytes().all(|c| c.is_ascii_alphabetic()); @@ -1190,8 +1191,8 @@ mod tests { assert_eq!(ftd1.key, ftd2.key); let scene = release_identity("p", r#"Some.Movie.2008.DVDRip.XviD-GRP [01/40] - "grp-sm.part01.rar" yEnc"#, "grp-sm.part01.rar"); assert_eq!(scene.name, "Some Movie 2008 DVDRip XviD GRP"); - assert!(is_poster_tag("PowBeertje80 Posted", "Bravo Hits Vol.14 2CD -1996-")); - assert!(!is_poster_tag("Audiofiles DIE ZEIT 35", "35_China_dl")); + assert!(is_poster_tag("PowBeertje80 Posted", "Bravo Hits Vol.14 2CD -1996-", false)); + assert!(!is_poster_tag("Audiofiles DIE ZEIT 35", "35_China_dl", false)); } #[test] @@ -1407,6 +1408,8 @@ mod image_set_tests { assert_ne!(gb("6c57319fbae505679737bd46a76193a1-u4e.part6.rar").key, gb("6fc0ff192a355703b3e81557893013b1-u4e.part6.rar").key); assert_ne!(gb("21.Jump.Street.2012.BDRip.AC3.German.XviD-POE.part01.rar").key, gb("Ice.Age.4.Voll.verschoben.2012.BDRip.AC3.German.XviD-POE.part01.rar").key); assert_eq!(gb("21.Jump.Street.2012.BDRip.AC3.German.XviD-POE.part01.rar").key, gb("21.Jump.Street.2012.BDRip.AC3.German.XviD-POE.par2").key); + let mac = |i: &str, n: &str| release_identity("p", &format!(r#"[1598]-[FULL]-[#a.b.teevee@EFNet]-[ MacGyver.S01E03.DVDRip.XviD-MEDiEVAL ]-[{i}/38] - "{n}" yEnc"#), n); + assert_eq!(mac("04", "sample.macgy.s01e03-med.avi").key, mac("05", "macgy.s01e03-med.r00").key); let pck = |i: &str, n: &str| release_identity("p", &format!(r#"(????) [{i}/2195] - "{n}" yEnc"#), n); assert_eq!(pck("0659", "DN.VPL PCK.1508").key, pck("0660", "DN.VPL PCK.1509").key); assert_eq!(pck("0659", "DN.VPL PCK.1508").name, "DN.VPL PCK.1508"); diff --git a/lib/release/identity.ts b/lib/release/identity.ts index 1cb12fc..92ae17d 100644 --- a/lib/release/identity.ts +++ b/lib/release/identity.ts @@ -238,7 +238,7 @@ const TAG_WORDS = new Set(['www', 'http', 'https', 'com', 'net', 'org', 'info', * boilerplate doesn't count. A number of 5+ digits is a per-post id * ("FTD 769997", "(781442)"), so never a constant tag. */ -export function isPosterTag(remainder: string, stem: string): boolean { +export function isPosterTag(remainder: string, stem: string, counted = false): boolean { const words = stem.toLowerCase().replace(/[^a-z0-9]+/g, ' ').trim() const compact = words.replace(/ /g, '') const whole = new Set(words.split(' ')) @@ -255,9 +255,10 @@ export function isPosterTag(remainder: string, stem: string): boolean { significant++ if (word.length >= 4 ? compact.includes(word) : whole.has(word)) shared++ } - // A tag of 4+ words may share one with the stem ("German Board - [Usenet4ever.info] und [SecretUsenet.com] - + // Without a counter, a tag of 4+ words may share one with the stem ("German Board - [Usenet4ever.info] und [SecretUsenet.com] - // "21.Jump.Street.2012.BDRip.AC3.German.XviD-POE.part01.rar"": the poster's uploads were releases of 1,535 files). - return shared === 0 || (shared === 1 && significant >= 4) + // With one, that's a name ("[ MacGyver.S01E03.DVDRip.XviD-MEDiEVAL ]-[04/38] - "sample.macgy.s01e03-med.avi""). + return shared === 0 || (shared === 1 && significant >= 4 && !counted) } /** @@ -344,7 +345,7 @@ export function releaseIdentity(input: ReleaseInput): ReleaseIdentity | null { // "055631a1_b6c820bc_a856086c_85112a5-u4e.part01.rar"": a day's uploads were one release; LOG.md 2026-10-12 (11)). const hashed = fileTotal === undefined && HASHED.test(stem) // A dated stem says which upload it is, short as it is ("09-30-2008_CTC.r00" under "#sterntuary - Coast To Coast Radio Show"). - const tag = hashed || (!image && !numbered && !AUDIO.test(input.name) && (describes(stem) || dated) && !looksRandom(stem) && isPosterTag(remainder, stem)) + const tag = hashed || (!image && !numbered && !AUDIO.test(input.name) && (describes(stem) || dated) && !looksRandom(stem) && isPosterTag(remainder, stem, fileTotal !== undefined)) // An image set without a counter: the image's name up to its last number, without numbers // ("Kitchen Hottie 1 set233-76-lg" → "Kitchen Hottie set", "bm_jessica_blb_h087" → "bm jessica blb h"). const prefix = image ? stem.replace(/\d+\D*$/, '').replace(/\d+/g, ' ').replace(/[\s._-]+/g, ' ').trim() : '' diff --git a/tests/unit/release/identity.spec.ts b/tests/unit/release/identity.spec.ts index 02fb312..f180050 100644 --- a/tests/unit/release/identity.spec.ts +++ b/tests/unit/release/identity.spec.ts @@ -333,6 +333,8 @@ test.group('release / par2 names', () => { assert.notEqual(gb('6c57319fbae505679737bd46a76193a1-u4e.part6.rar').key, gb('6fc0ff192a355703b3e81557893013b1-u4e.part6.rar').key) assert.notEqual(gb('21.Jump.Street.2012.BDRip.AC3.German.XviD-POE.part01.rar').key, gb('Ice.Age.4.Voll.verschoben.2012.BDRip.AC3.German.XviD-POE.part01.rar').key) assert.equal(gb('21.Jump.Street.2012.BDRip.AC3.German.XviD-POE.part01.rar').key, gb('21.Jump.Street.2012.BDRip.AC3.German.XviD-POE.par2').key) + const mac = (i: string, n: string) => id(`[1598]-[FULL]-[#a.b.teevee@EFNet]-[ MacGyver.S01E03.DVDRip.XviD-MEDiEVAL ]-[${i}/38] - "${n}" yEnc`, n) + assert.equal(mac('04', 'sample.macgy.s01e03-med.avi').key, mac('05', 'macgy.s01e03-med.r00').key) const pck = (i: string, n: string) => id(`(????) [${i}/2195] - "${n}" yEnc`, n) assert.equal(pck('0659', 'DN.VPL PCK.1508').key, pck('0660', 'DN.VPL PCK.1509').key) assert.equal(pck('0659', 'DN.VPL PCK.1508').name, 'DN.VPL PCK.1508')