From 8a714d645570b957faa1ac56c8c2ccffad363fdd Mon Sep 17 00:00:00 2001 From: imSp4rky Date: Tue, 31 Mar 2026 09:13:44 -0600 Subject: [PATCH] fix(template): detect folder spacer from template separators, not raw string The previous heuristic checked the raw template string for dots, which could match dots inside variable names or title content, causing Plex-friendly folder names to incorrectly use dots as spacers. Now strips template variables first and checks only the separators between them to determine user intent. --- unshackle/core/titles/episode.py | 14 ++++++-------- unshackle/core/titles/movie.py | 9 +++++---- unshackle/core/titles/song.py | 9 +++++---- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/unshackle/core/titles/episode.py b/unshackle/core/titles/episode.py index 23cd601..814c381 100644 --- a/unshackle/core/titles/episode.py +++ b/unshackle/core/titles/episode.py @@ -107,10 +107,9 @@ class Episode(Title): folder_name = formatter.format(context) - if '.' in config.folder_template and ' ' not in config.folder_template: - return sanitize_filename(folder_name, ".") - else: - return sanitize_filename(folder_name, " ") + separators = re.sub(r'\{[^}]*\}', '', config.folder_template) + spacer = "." if "." in separators and " " not in separators else " " + return sanitize_filename(folder_name, spacer) series_template = config.output_template.get("series") if series_template: @@ -130,10 +129,9 @@ class Episode(Title): folder_name = formatter.format(context) - if '.' in series_template and ' ' not in series_template: - return sanitize_filename(folder_name, ".") - else: - return sanitize_filename(folder_name, " ") + separators = re.sub(r'\{[^}]*\}', '', derived_template) + spacer = "." if "." in separators and " " not in separators else " " + return sanitize_filename(folder_name, spacer) else: name = f"{self.title}" if self.year: diff --git a/unshackle/core/titles/movie.py b/unshackle/core/titles/movie.py index 8cf8540..d170b99 100644 --- a/unshackle/core/titles/movie.py +++ b/unshackle/core/titles/movie.py @@ -1,3 +1,4 @@ +import re from abc import ABC from typing import Any, Iterable, Optional, Union @@ -63,10 +64,10 @@ class Movie(Title): formatter = TemplateFormatter(config.folder_template) context = self._build_template_context(media_info, show_service) folder_name = formatter.format(context) - if '.' in config.folder_template and ' ' not in config.folder_template: - return sanitize_filename(folder_name, ".") - else: - return sanitize_filename(folder_name, " ") + + separators = re.sub(r'\{[^}]*\}', '', config.folder_template) + spacer = "." if "." in separators and " " not in separators else " " + return sanitize_filename(folder_name, spacer) name = f"{self.name}" if self.year: name += f" ({self.year})" diff --git a/unshackle/core/titles/song.py b/unshackle/core/titles/song.py index 82ae62d..3e1712a 100644 --- a/unshackle/core/titles/song.py +++ b/unshackle/core/titles/song.py @@ -1,3 +1,4 @@ +import re from abc import ABC from typing import Any, Iterable, Optional, Union @@ -98,10 +99,10 @@ class Song(Title): formatter = TemplateFormatter(config.folder_template) context = self._build_template_context(media_info, show_service) folder_name = formatter.format(context) - if '.' in config.folder_template and ' ' not in config.folder_template: - return sanitize_filename(folder_name, ".") - else: - return sanitize_filename(folder_name, " ") + + separators = re.sub(r'\{[^}]*\}', '', config.folder_template) + spacer = "." if "." in separators and " " not in separators else " " + return sanitize_filename(folder_name, spacer) name = f"{self.artist} - {self.album}" if self.year: name += f" ({self.year})"