/** * Extract a JAV product code from a filename. * Handles common patterns: "SSIS-001.jpg", "[ABC] DEF-123.png", "ssis001 cover.jpg", * "abp-456_cover.jpeg", and pre-fixes like "FHD-MIDV-123.jpg". * * Returns the canonical "PREFIX-NUMBER" form (uppercased), or null if no match. */ // Prefix must start with a letter and may contain digits (e.g. "T28", "ABP", // "MIAA"). Total prefix length 2-6 alphanumerics. The numeric tail is 3-5 // digits, with an optional single-letter suffix for variant releases — // "IBW-610z" (z-version / re-cut), "ABP-456a" (part-a), etc. Suffix is // preserved in the canonical form so e.g. IBW-610 and IBW-610Z stay // distinct (they're different versions of the same release). const CODE_RE = /\b([A-Za-z][A-Za-z0-9]{1,5})[-_ ]?(\d{3,5})([a-zA-Z])?\b/; const QUALITY_PREFIXES = new Set(["fhd", "hd", "sd", "uhd", "4k", "1080p", "720p", "480p", "hevc", "x265", "x264"]); /** * Canonicalise an already-known code to "PREFIX-NUMBER" with the number * left-padded to a minimum of 3 digits and the prefix uppercased. Inputs * coming from NFO `` tags can arrive in any of "MIAA-291", "miaa291", * "MIAA-00291", etc.; we want them all to compare equal so the collision * detector isn't fooled by formatting drift. */ export function normalizeCode(raw: string | null | undefined): string | null { if (!raw) return null; const m = raw.trim().match(CODE_RE); if (!m) return null; const suffix = (m[3] ?? "").toUpperCase(); return `${m[1].toUpperCase()}-${m[2].padStart(3, "0")}${suffix}`; } export function extractCode(filename: string): string | null { const base = filename.replace(/\.[^.]+$/, ""); // Walk left-to-right, skipping quality prefixes that look like codes (e.g. "FHD-"). let cursor = 0; while (cursor < base.length) { const m = base.slice(cursor).match(CODE_RE); if (!m) return null; const prefix = m[1]; const num = m[2]; const suffix = (m[3] ?? "").toUpperCase(); if (QUALITY_PREFIXES.has(prefix.toLowerCase())) { cursor += (m.index ?? 0) + m[0].length; continue; } return `${prefix.toUpperCase()}-${num.padStart(3, "0")}${suffix}`; } return null; }