Image sets: keyed by set without words around them; px, ImageVenue, spaced repeats
- An image whose subject has no words ("##[ "diana-040-001.jpg" (01/68)")
is keyed by its set, not its name without numbers: a poster's 263 diana
sets were one release of 17,808 images.
- imageSet strips "-2048px" and ImageVenue's "_123_244lo", and reads a
spaced suffix ("she has sensual legs 172 _ 172") as one.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
108d798d97
commit
18a146e130
3 files changed
+51
-14
No files matched your search
+28
-7
@@ -419,7 +419,7 @@ pub fn image_set(stem: &str) -> String {
|
||||
// .replace(/(\d+)\s*of\s*\d+/gi, '$1')
|
||||
// Suffixes that number no image: a copy's ("…[1]"), a resolution ("…_2000x1500"), a constant one ("…_00").
|
||||
let mut s = stem.as_bytes().to_vec();
|
||||
for re in [&*COPY_MARK, &*RESOLUTION, &*ZERO_SUFFIX] {
|
||||
for re in [&*COPY_MARK, &*RESOLUTION, &*IMAGEVENUE, &*ZERO_SUFFIX] {
|
||||
s = re.replace(&s, &b""[..]).into_owned();
|
||||
}
|
||||
// A counter in the name counts the images: the set is the text before it ("Set 008 10of63 new0464").
|
||||
@@ -430,13 +430,20 @@ pub fn image_set(stem: &str) -> String {
|
||||
let s_ts = TIMESTAMP.replace(&s, &b""[..]).into_owned();
|
||||
s = s_ts;
|
||||
loop {
|
||||
// /[_-](\d+)$/
|
||||
// /\s*([_-])\s*(\d+)$/ (also spaced: "she has sensual legs 172 _ 172")
|
||||
let digits = s.iter().rev().take_while(|c| c.is_ascii_digit()).count();
|
||||
if digits == 0 || s.len() <= digits || !matches!(s[s.len() - digits - 1], b'_' | b'-') {
|
||||
if digits == 0 {
|
||||
break;
|
||||
}
|
||||
let ws = |c: &u8| matches!(c, b' ' | b'\t' | b'\n' | b'\r' | 0x0b | 0x0c);
|
||||
let sep_end = s.len() - digits - s[..s.len() - digits].iter().rev().take_while(|c| ws(c)).count();
|
||||
if sep_end == 0 || !matches!(s[sep_end - 1], b'_' | b'-') {
|
||||
break;
|
||||
}
|
||||
let sep = s[sep_end - 1];
|
||||
let before_end = sep_end - 1 - s[..sep_end - 1].iter().rev().take_while(|c| ws(c)).count();
|
||||
let n = &s[s.len() - digits..];
|
||||
let before = &s[..s.len() - digits - 1];
|
||||
let before = &s[..before_end];
|
||||
// /(\d+)\D*$/: the last digit run before
|
||||
let Some(last) = before.iter().rposition(u8::is_ascii_digit) else { break };
|
||||
let start = before[..=last].iter().rposition(|c| !c.is_ascii_digit()).map_or(0, |i| i + 1);
|
||||
@@ -444,7 +451,7 @@ pub fn image_set(stem: &str) -> String {
|
||||
// A repeat: the same number, or the end of the one before (054001 ends in 1).
|
||||
let same = trim_zeros(n) == trim_zeros(previous) || previous.ends_with(n);
|
||||
// A renumbering right after the number ("kate108lg029_28"): both count the images.
|
||||
let renumbered = s[s.len() - digits - 1] == b'_' && n[0] != b'0' && last + 1 == before.len();
|
||||
let renumbered = sep == b'_' && n[0] != b'0' && last + 1 == before.len();
|
||||
let year = n.len() == 4 && (n.starts_with(b"19") || n.starts_with(b"20"));
|
||||
if same || renumbered || year || n.len() >= 4 {
|
||||
let cut = before.len();
|
||||
@@ -470,7 +477,8 @@ fn trim_zeros(d: &[u8]) -> &[u8] {
|
||||
|
||||
static TIMESTAMP: LazyLock<Regex> = LazyLock::new(|| re(r"[-_. ]?(?:19|20)[0-9]{2}[-._ ](?:0?[1-9]|1[0-2])[-._ ][0-9]{1,2}(?:[-._ ][0-9]{1,2})*$"));
|
||||
static COPY_MARK: LazyLock<Regex> = LazyLock::new(|| re(r"SP*[\[(][0-9]+[\])]$"));
|
||||
static RESOLUTION: LazyLock<Regex> = LazyLock::new(|| re(r"(?i)[_-][0-9]{3,4}x[0-9]{3,4}$"));
|
||||
static RESOLUTION: LazyLock<Regex> = LazyLock::new(|| re(r"(?i)[_-][0-9]{3,4}(?:x[0-9]{3,4}|px)$"));
|
||||
static IMAGEVENUE: LazyLock<Regex> = LazyLock::new(|| re(r"(?i)_123_[0-9]+lo$"));
|
||||
static ZERO_SUFFIX: LazyLock<Regex> = LazyLock::new(|| re(r"[_-]0+$"));
|
||||
static NAME_COUNTER: LazyLock<Regex> = LazyLock::new(|| re(r"(?i)([0-9]+)SP*ofSP*[0-9]+|[\[(]?SP*[0-9]+SP*/SP*[0-9]+SP*[\])]?"));
|
||||
|
||||
@@ -672,8 +680,11 @@ pub fn release_identity(poster: &str, subject: &str, name: &str) -> Release {
|
||||
}
|
||||
}
|
||||
if image {
|
||||
// Keyed by its set when its name has one ("diana-040-001.jpg").
|
||||
let name = if prefix.is_empty() { stem.clone() } else { prefix.clone() };
|
||||
return Release { key: hash(&["stem", poster, &name]), name, source: "stem", file_total };
|
||||
let set = image_set(&stem);
|
||||
let key = if set.is_empty() { hash(&["stem", poster, &name]) } 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.
|
||||
if test(&AUDIO, name) {
|
||||
@@ -1204,6 +1215,9 @@ mod image_set_tests {
|
||||
("New Folder (17) sexypattycake_0903040445[1]", "New Folder ("),
|
||||
("092_081_2000x1500", "092_"),
|
||||
("KP0027_197_00", "KP"),
|
||||
("01079-106-2048px", "01079-"),
|
||||
("she has sensual legs 172 _ 172", "she has sensual legs "),
|
||||
("jamie.lee.curtis_the.tailor.of.panama_17_123_244lo", "jamie.lee.curtis_the.tailor.of.panama_"),
|
||||
("JimAndJoey Kindly Husband-to-Be", ""),
|
||||
] {
|
||||
assert_eq!(image_set(stem), want, "{stem}");
|
||||
@@ -1219,6 +1233,13 @@ mod image_set_tests {
|
||||
assert_eq!(mint("JimAndJoey Kindly Husband-to-Be.JPG").key, mint("Oops OnlyOneMore.JPG").key);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn images_without_words_by_their_set() {
|
||||
let id = |n: &str, c: &str| release_identity("p", &format!(r#"##[ "{n}" ({c})"#), n);
|
||||
assert_eq!(id("diana-040-001.jpg", "01/68").key, id("diana-040-002.jpg", "02/68").key);
|
||||
assert_ne!(id("diana-040-001.jpg", "01/68").key, id("diana-407-081.jpg", "81/82").key);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unquoted_names_are_no_counters() {
|
||||
let shy = |n: &str| release_identity("p", &format!("{n} hardcore SHYLA STYLEZ & SHY LOVE"), n);
|
||||
|
||||
Reference in new issue
Block a user