Identity: unquoted names are no counters; renumbered and timestamped image sets
- The file total is read from the subject without the file name, as with a
quoted one: "shyla-shy-09-0195.jpg hardcore …" read as 9 of 195 made each
of 866 images a release of its own.
- imageSet: "_N" right after a number is a renumbering ("kate108lg029_28"
once an image was skipped), and a trailing camera timestamp
("kurozo-2006-7-26-15-21") numbers no set.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
f094fb4593
commit
e72a9b1ef5
3 files changed
+51
-16
No files matched your search
+25
-6
@@ -418,6 +418,9 @@ static DOCUMENT: LazyLock<Regex> = LazyLock::new(|| re(r"(?i)\.(pdf|epub|mobi|az
|
||||
pub fn image_set(stem: &str) -> String {
|
||||
// .replace(/(\d+)\s*of\s*\d+/gi, '$1')
|
||||
let mut s = OF_TOTAL.replace_all(stem.as_bytes(), &b"$1"[..]).into_owned();
|
||||
// A camera's timestamp ("kurozo-2006-7-26-15-21"): the date and the time after it number no set.
|
||||
let s_ts = TIMESTAMP.replace(&s, &b""[..]).into_owned();
|
||||
s = s_ts;
|
||||
loop {
|
||||
// /[_-](\d+)$/
|
||||
let digits = s.iter().rev().take_while(|c| c.is_ascii_digit()).count();
|
||||
@@ -432,8 +435,10 @@ pub fn image_set(stem: &str) -> String {
|
||||
let previous = &before[start..=last];
|
||||
// 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 year = n.len() == 4 && (n.starts_with(b"19") || n.starts_with(b"20"));
|
||||
if same || year || n.len() >= 4 {
|
||||
if same || renumbered || year || n.len() >= 4 {
|
||||
let cut = before.len();
|
||||
s.truncate(cut);
|
||||
} else {
|
||||
@@ -455,6 +460,7 @@ fn trim_zeros(d: &[u8]) -> &[u8] {
|
||||
t
|
||||
}
|
||||
|
||||
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 OF_TOTAL: LazyLock<Regex> = LazyLock::new(|| re(r"(?i)([0-9]+)SP*ofSP*[0-9]+"));
|
||||
|
||||
fn image_prefix(stem: &str) -> String {
|
||||
@@ -604,18 +610,21 @@ 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 file_total = counter_total(subject).and_then(|t| t.parse::<i64>().ok());
|
||||
let stem = file_stem(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.
|
||||
let remainder = if subject.contains(&format!("\"{name}\"")) {
|
||||
subject_remainder(subject)
|
||||
let named = if subject.contains(&format!("\"{name}\"")) {
|
||||
subject.to_string()
|
||||
} else {
|
||||
let collapsed = js::collapse_spaces(name);
|
||||
let collapsed = js::trim(&collapsed);
|
||||
let without = if subject.contains(name) { subject.replacen(name, " ", 1) } else { subject.replacen(collapsed, " ", 1) };
|
||||
subject_remainder(&without.replace('"', " "))
|
||||
without.replace('"', " ")
|
||||
};
|
||||
let remainder = subject_remainder(&named);
|
||||
// Counted without the file name: "shyla-shy-09-0195.jpg hardcore …" is no "9 of 195".
|
||||
let total = counter_total(&named);
|
||||
let file_total = total.as_ref().and_then(|t| t.parse::<i64>().ok());
|
||||
// A document or comic is a release of its own.
|
||||
if test(&DOCUMENT, name) {
|
||||
let shown = replace(&DOCUMENT, &stem, "", false);
|
||||
@@ -643,7 +652,7 @@ pub fn release_identity(poster: &str, subject: &str, name: &str) -> Release {
|
||||
let one_word = image && remainder.len() >= 3 && remainder.bytes().all(|c| c.is_ascii_alphabetic());
|
||||
if !tag && (names_release(&remainder) || one_word) {
|
||||
// Without a counter an image's set: its name up to its last number, digits kept; none without numbers.
|
||||
let bound = counter_total(subject).unwrap_or_else(|| if image { image_set(&stem) } else { String::new() });
|
||||
let bound = total.clone().unwrap_or_else(|| if image { image_set(&stem) } else { String::new() });
|
||||
return Release { key: hash(&["subject", poster, &remainder, &bound]), name: remainder, source: "subject", file_total };
|
||||
}
|
||||
if let Some(total) = post_total.filter(|&n| n != 0 && !tag) {
|
||||
@@ -1175,6 +1184,9 @@ mod image_set_tests {
|
||||
("IMG_2676", "IMG_"),
|
||||
("2877-041", "2877-"),
|
||||
("051 - White leather kate054001_1_1", "051 - White leather kate"),
|
||||
("108 - Schoolwall kate108lg029_28", "108 - Schoolwall kate108lg"),
|
||||
("kurozo-2006-7-26-15-21", ""),
|
||||
("bwp2_037_5", "bwp2_"),
|
||||
("JimAndJoey Kindly Husband-to-Be", ""),
|
||||
] {
|
||||
assert_eq!(image_set(stem), want, "{stem}");
|
||||
@@ -1190,6 +1202,13 @@ mod image_set_tests {
|
||||
assert_eq!(mint("JimAndJoey Kindly Husband-to-Be.JPG").key, mint("Oops OnlyOneMore.JPG").key);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unquoted_names_are_no_counters() {
|
||||
let shy = |n: &str| release_identity("p", &format!("{n} hardcore SHYLA STYLEZ & SHY LOVE"), n);
|
||||
assert_eq!(shy("shyla-shy-09-0195.jpg").key, shy("shyla-shy-09-0766.jpg").key);
|
||||
assert_eq!(shy("shyla-shy-09-0195.jpg").file_total, None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dates_are_no_counters() {
|
||||
use super::counter_total;
|
||||
|
||||
Reference in new issue
Block a user