import { isGenericName } from './identity.js' /** * Obfuscated names: one long token of mixed letters and digits, no * separators, and the other generated shapes seen on Usenet (LOG.md * 2026-10-01 (3)). Kept in step with SQL's is_readable_name(). */ /** How often a token goes from a letter to a digit or back. */ function letterDigitSwitches(token: string): number { let switches = 0 for (let i = 1; i < token.length; i++) { const a = token.charCodeAt(i - 1) <= 57 const b = token.charCodeAt(i) <= 57 if (a !== b) switches++ } return switches } export function looksRandom(name: string): boolean { // An unknown short extension (e.g. ".bin") says nothing about the name. name = name.replace(/\.[A-Za-z0-9]{1,4}$/, '') // VIDEO_TS, Sample, CD1: real words, but no name. if (isGenericName(name)) return true if (/^[0-9a-f]{16,}$/i.test(name)) return true // 6327d9fa2d6acf3e9a61fb053359d5e7.1790574045 (hex and a Unix time) if (/^[0-9a-f]{16,}\.\d{9,}$/i.test(name)) return true // UUIDs if (/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(name)) return true // 1650777167 (yEncBin), "83111763 n" (rclone uploads) if (/^\d{6,}( n)?$/.test(name)) return true // prvjr7hapd0i1ny14pz4, and rclone's long base32 names if (/^[a-z0-9]{12,}$/.test(name) && (name.match(/\d/g)?.length ?? 0) >= 2 && (name.match(/[a-z]/g)?.length ?? 0) >= 4) return true // wHJ7s71sAGE: short, but capitals all over the token, not only at word starts if (/^[A-Za-z0-9]{8,15}$/.test(name) && /\d/.test(name) && /[a-z]/.test(name) && (name.slice(1).match(/[A-Z]/g)?.length ?? 0) >= 3) return true // 51294P1CUKR2R35X: capitals and digits only, switching between them all over the token // (COD4MW2REMASTERED switches 4 times, BEATLES1964REMASTER twice). if (/^[A-Z0-9]{12,}$/.test(name) && letterDigitSwitches(name) >= 6) return true if (!/^[A-Za-z0-9]{16,}$/.test(name) || !/[a-z]/.test(name) || !/[A-Z]/.test(name)) return false // Digits, or many capitals without separators (e.g. RmISakytFwXSCEzjVEpaKk). return /\d/.test(name) || (name.match(/[A-Z]/g) ?? []).length >= 6 }