diff --git a/bin/nn b/bin/nn index 044b559..1c4b140 100755 --- a/bin/nn +++ b/bin/nn @@ -26,6 +26,9 @@ TELEGRAM_PATTERN = re.compile( NORMALIZED = re.compile(r'^\d{4}-\d{2}-\d{2} .+') +# Windows hidden-file attribute, mirrored from the stat module. +FILE_ATTRIBUTE_HIDDEN = 0x2 + STATUS_RENAME = 'rename' STATUS_ALREADY = 'skip (already normalized)' STATUS_NO_MATCH = 'skip (no rule matched)' @@ -148,7 +151,19 @@ def get_date_for_file(filepath, parse_mode): return None -def collect_files(paths): +def is_hidden(filepath): + """Check whether a file is hidden (dotfile, or hidden attribute on Windows).""" + if filepath.name.startswith('.'): + return True + + try: + attrs = filepath.stat().st_file_attributes + except (AttributeError, OSError): + return False + return bool(attrs & FILE_ATTRIBUTE_HIDDEN) + + +def collect_files(paths, include_hidden=False): """Resolve the list of files to process.""" if not paths: paths = ['.'] @@ -157,8 +172,12 @@ def collect_files(paths): for path in paths: candidate = Path(path) if candidate.is_dir(): - files.extend(sorted(file for file in candidate.iterdir() if file.is_file())) + files.extend(sorted( + file for file in candidate.iterdir() + if file.is_file() and (include_hidden or not is_hidden(file)) + )) elif candidate.is_file(): + # Explicitly named files are always processed. files.append(candidate) return files @@ -318,6 +337,12 @@ def main(): action='store_true', help='Force numbering even for already-normalized files (used with -n).', ) + parser.add_argument( + '-a', + '--all', + action='store_true', + help='Include hidden files when scanning directories.', + ) parser.add_argument( 'files', nargs='*', @@ -326,7 +351,7 @@ def main(): args = parser.parse_args() - files = collect_files(args.files) + files = collect_files(args.files, args.all) if not files: print('No files found.') sys.exit(0)