"""Shared utilities for file naming and organization.""" import os import re from pathlib import Path import mutagen def sanitize_filename(name): """Remove characters prohibited in Windows filenames.""" name = re.sub(r'[<>:"/\\|?*]', '_', name) return name.strip().strip('.') def rename_from_metadata(file_path): """Rename an audio file to 'Title - Artist1, Artist2.ext' using embedded metadata. Returns the new Path (or original if rename not possible). """ file_path = Path(file_path) audio = mutagen.File(str(file_path), easy=True) if audio is None: return file_path try: title = audio.get("title", [None])[0] artist = audio.get("artist", [None])[0] except (IndexError, KeyError): return file_path if not title or not artist: return file_path new_name = sanitize_filename(f"{title} - {artist}{file_path.suffix}") new_path = file_path.parent / new_name if new_path == file_path: return file_path # Handle collisions counter = 2 base_stem = new_path.stem while new_path.exists(): new_path = new_path.with_stem(f"{base_stem} ({counter})") counter += 1 file_path.rename(new_path) return new_path def cleanup_empty_dirs(directory): """Remove empty subdirectories (bottom-up).""" directory = Path(directory) for dirpath, dirnames, filenames in os.walk(str(directory), topdown=False): dirpath = Path(dirpath) if dirpath == directory: continue if not any(dirpath.iterdir()): dirpath.rmdir()