diff --git a/picard/ui/options/renaming_compat.py b/picard/ui/options/renaming_compat.py index 201464253..1b428f153 100644 --- a/picard/ui/options/renaming_compat.py +++ b/picard/ui/options/renaming_compat.py @@ -43,6 +43,7 @@ from PyQt5 import ( from picard.config import ( BoolOption, Option, + TextOption, get_config, ) from picard.const.sys import IS_WIN @@ -73,6 +74,7 @@ class RenamingCompatOptionsPage(OptionsPage): BoolOption("setting", "windows_long_paths", system_supports_long_paths() if IS_WIN else False), BoolOption("setting", "ascii_filenames", False), BoolOption("setting", "replace_spaces_with_underscores", False), + TextOption("setting", "replace_dir_separator", DEFAULT_REPLACEMENT), Option("setting", "win_compat_replacements", { '*': DEFAULT_REPLACEMENT, ':': DEFAULT_REPLACEMENT, @@ -96,6 +98,7 @@ class RenamingCompatOptionsPage(OptionsPage): self.ui.windows_compatibility.toggled.connect(self.on_options_changed) self.ui.windows_long_paths.toggled.connect(self.on_options_changed) self.ui.replace_spaces_with_underscores.toggled.connect(self.on_options_changed) + self.ui.replace_dir_separator.textChanged.connect(self.on_options_changed) self.ui.btn_windows_compatibility_change.clicked.connect(self.open_win_compat_dialog) def load(self): @@ -113,6 +116,7 @@ class RenamingCompatOptionsPage(OptionsPage): self.ui.windows_long_paths.setChecked(config.setting["windows_long_paths"]) self.ui.ascii_filenames.setChecked(config.setting["ascii_filenames"]) self.ui.replace_spaces_with_underscores.setChecked(config.setting["replace_spaces_with_underscores"]) + self.ui.replace_dir_separator.setText(config.setting["replace_dir_separator"]) self.ui.windows_long_paths.toggled.connect(self.toggle_windows_long_paths) def save(self): @@ -144,6 +148,7 @@ class RenamingCompatOptionsPage(OptionsPage): 'windows_compatibility': self.ui.windows_compatibility.isChecked(), 'windows_long_paths': self.ui.windows_long_paths.isChecked(), 'replace_spaces_with_underscores': self.ui.replace_spaces_with_underscores.isChecked(), + 'replace_dir_separator': self.ui.replace_dir_separator.text(), 'win_compat_replacements': self.win_compat_replacements, } diff --git a/picard/ui/ui_options_renaming_compat.py b/picard/ui/ui_options_renaming_compat.py index c7bd5b9bd..420524d17 100644 --- a/picard/ui/ui_options_renaming_compat.py +++ b/picard/ui/ui_options_renaming_compat.py @@ -44,6 +44,28 @@ class Ui_RenamingCompatOptionsPage(object): self.replace_spaces_with_underscores = QtWidgets.QCheckBox(RenamingCompatOptionsPage) self.replace_spaces_with_underscores.setObjectName("replace_spaces_with_underscores") self.verticalLayout_5.addWidget(self.replace_spaces_with_underscores) + self.horizontalLayout_2 = QtWidgets.QHBoxLayout() + self.horizontalLayout_2.setObjectName("horizontalLayout_2") + self.label_replace_dir_separator = QtWidgets.QLabel(RenamingCompatOptionsPage) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label_replace_dir_separator.sizePolicy().hasHeightForWidth()) + self.label_replace_dir_separator.setSizePolicy(sizePolicy) + self.label_replace_dir_separator.setObjectName("label_replace_dir_separator") + self.horizontalLayout_2.addWidget(self.label_replace_dir_separator) + self.replace_dir_separator = QtWidgets.QLineEdit(RenamingCompatOptionsPage) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.replace_dir_separator.sizePolicy().hasHeightForWidth()) + self.replace_dir_separator.setSizePolicy(sizePolicy) + self.replace_dir_separator.setMaximumSize(QtCore.QSize(20, 16777215)) + self.replace_dir_separator.setText("_") + self.replace_dir_separator.setMaxLength(1) + self.replace_dir_separator.setObjectName("replace_dir_separator") + self.horizontalLayout_2.addWidget(self.replace_dir_separator) + self.verticalLayout_5.addLayout(self.horizontalLayout_2) spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) self.verticalLayout_5.addItem(spacerItem) self.example_selection_note = QtWidgets.QLabel(RenamingCompatOptionsPage) @@ -65,3 +87,4 @@ class Ui_RenamingCompatOptionsPage(object): self.btn_windows_compatibility_change.setText(_("Customize...")) self.windows_long_paths.setText(_("Allow paths longer than 259 characters")) self.replace_spaces_with_underscores.setText(_("Replace spaces with underscores")) + self.label_replace_dir_separator.setText(_("Replace directory separators with:")) diff --git a/picard/util/scripttofilename.py b/picard/util/scripttofilename.py index a72c39497..e76fb6ff7 100644 --- a/picard/util/scripttofilename.py +++ b/picard/util/scripttofilename.py @@ -57,9 +57,12 @@ def script_to_filename_with_metadata(naming_format, metadata, file=None, setting # make sure every metadata can safely be used in a path name win_compat = IS_WIN or settings["windows_compatibility"] new_metadata = Metadata() + replace_dir_separator = settings["replace_dir_separator"] for name in metadata: - new_metadata[name] = [sanitize_filename(str(v), win_compat=win_compat) - for v in metadata.getall(name)] + new_metadata[name] = [ + sanitize_filename(str(v), repl=replace_dir_separator, win_compat=win_compat) + for v in metadata.getall(name) + ] naming_format = naming_format.replace("\t", "").replace("\n", "") filename = ScriptParser().eval(naming_format, new_metadata, file) if settings["ascii_filenames"]: diff --git a/test/formats/common.py b/test/formats/common.py index 0cdde9e1f..9bdad58c9 100644 --- a/test/formats/common.py +++ b/test/formats/common.py @@ -63,6 +63,7 @@ settings = { 'remove_wave_riff_info': False, 'wave_riff_info_encoding': 'iso-8859-1', 'replace_spaces_with_underscores': False, + 'replace_dir_separator': '_', 'win_compat_replacements': {}, } diff --git a/test/test_coverart_image.py b/test/test_coverart_image.py index 8764bd9c4..952706f2b 100644 --- a/test/test_coverart_image.py +++ b/test/test_coverart_image.py @@ -169,6 +169,7 @@ class CoverArtImageTest(PicardTestCase): 'win_compat_replacements': {}, 'windows_long_paths': False, 'replace_spaces_with_underscores': False, + 'replace_dir_separator': '_', 'enabled_plugins': [], 'ascii_filenames': False, 'save_images_overwrite': False, @@ -202,6 +203,7 @@ class CoverArtImageMakeFilenameTest(PicardTestCase): 'enabled_plugins': [], 'ascii_filenames': False, 'replace_spaces_with_underscores': False, + 'replace_dir_separator': '_', }) def compare_paths(self, path1, path2): diff --git a/test/test_file.py b/test/test_file.py index 952cacd44..4b115a130 100644 --- a/test/test_file.py +++ b/test/test_file.py @@ -213,6 +213,7 @@ class FileNamingTest(PicardTestCase): 'win_compat_replacements': {}, 'windows_long_paths': False, 'replace_spaces_with_underscores': False, + 'replace_dir_separator': '_', 'file_renaming_scripts': {'test_id': {'script': '%album%/%title%'}}, 'selected_file_naming_script_id': 'test_id', }) diff --git a/test/test_scripttofilename.py b/test/test_scripttofilename.py index 214a593ed..3c1277c66 100644 --- a/test/test_scripttofilename.py +++ b/test/test_scripttofilename.py @@ -41,6 +41,7 @@ settings = { 'windows_compatibility': False, 'win_compat_replacements': {}, 'replace_spaces_with_underscores': False, + 'replace_dir_separator': '_', } @@ -142,6 +143,14 @@ class ScriptToFilenameTest(PicardTestCase): filename = script_to_filename('%artist%', metadata, settings=settings) self.assertEqual('The_New_Artist', filename) + def test_replace_dir_separator(self): + metadata = Metadata() + metadata['artist'] = 'AC/DC' + settings = config.setting.copy() + settings['replace_dir_separator'] = '-' + filename = script_to_filename('/music/%artist%', metadata, settings=settings) + self.assertEqual('/music/AC-DC', filename) + @unittest.skipUnless(IS_WIN, "windows test") def test_ascii_win_save(self): self._test_ascii_windows_compatibility() diff --git a/ui/options_renaming_compat.ui b/ui/options_renaming_compat.ui index af560d478..8d12dffb6 100644 --- a/ui/options_renaming_compat.ui +++ b/ui/options_renaming_compat.ui @@ -19,7 +19,7 @@ 0 - + @@ -71,6 +71,45 @@ + + + + + + + 0 + 0 + + + + Replace directory separators with: + + + + + + + + 0 + 0 + + + + + 20 + 16777215 + + + + _ + + + 1 + + + + +