From 8a39f7c41e566487984561fa1e6ec75e22d61e69 Mon Sep 17 00:00:00 2001 From: dschlueter Date: Tue, 17 Feb 2026 23:25:28 +0100 Subject: [PATCH] Sanitize filenames: replace spaces/punctuation with underscores MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace all non-word characters (spaces, punctuation, brackets, etc.) with underscores in track titles, album names and artist names. Collapse consecutive underscores to one, strip leading/trailing ones. Umlauts (ä, ö, ü, ß) and digits are preserved. Also use underscore instead of space between track number and title. Co-Authored-By: Claude Sonnet 4.5 --- src/musiksammlung/organizer.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/musiksammlung/organizer.py b/src/musiksammlung/organizer.py index 1c00419..93f4ac5 100644 --- a/src/musiksammlung/organizer.py +++ b/src/musiksammlung/organizer.py @@ -38,8 +38,14 @@ class DiscCheck: def _sanitize_filename(name: str) -> str: - """Entfernt problematische Zeichen aus Dateinamen.""" - return re.sub(r'[<>:"/\\|?*]', "_", name).strip() + """Ersetzt Sonderzeichen und Leerzeichen durch Unterstriche. + + Buchstaben (inkl. Umlaute), Ziffern und bestehende Unterstriche bleiben erhalten. + Mehrere aufeinanderfolgende Unterstriche werden zu einem zusammengezogen. + """ + name = re.sub(r'[^\w]', '_', name) # alles außer Buchstaben/Ziffern/_ → _ + name = re.sub(r'_+', '_', name) # mehrere _ → einer + return name.strip('_') def discover_audio_files(directory: Path) -> list[Path]: @@ -118,7 +124,7 @@ def build_mapping( for audio_file, track in zip(audio_files, disc.tracks): safe_title = _sanitize_filename(track.title) - new_name = f"{track.track_number:02d} {safe_title}{audio_file.suffix}" + new_name = f"{track.track_number:02d}_{safe_title}{audio_file.suffix}" mapping[audio_file] = target_dir / new_name return mapping