]> git.draconx.ca Git - picard-plugins.git/blobdiff - tweak-filename-filter.py
tweak-filename-filter: Update for picard 2.3.1
[picard-plugins.git] / tweak-filename-filter.py
index 5777bb7757bee59fd73d920fe8455e5d62196133..f1ad2dfd221b3aeb0e14562ec056e047fc47b0ea 100644 (file)
@@ -1,12 +1,12 @@
 # -*- coding: utf-8 -*-
 #
-# Copyright © 2018 Nick Bowler
+# Copyright © 2018-2020 Nick Bowler
 #
 # License GPLv3+: GNU General Public License version 3 or any later version.
 # This is free software: you are free to change and redistribute it.
 # There is NO WARRANTY, to the extent permitted by law.
 
-PLUGIN_NAME = u"Tweak filename filter"
+PLUGIN_NAME = u"Tweak Filename Filter"
 PLUGIN_AUTHOR = u"Nick Bowler"
 PLUGIN_DESCRIPTION = u'''<p>Adds additional options to tweak file naming.</p>
 <p>Currently, this overrides the default methods to substitute forward and
@@ -23,40 +23,137 @@ true)</dd>
 
 </dl>
 '''
-PLUGIN_VERSION = "0.1"
-PLUGIN_API_VERSIONS = ["1.0", "2.0"]
+PLUGIN_VERSION = "2"
+PLUGIN_API_VERSIONS = ["2.0"]
 PLUGIN_LICENSE = "GPL-3.0-or-later"
 
+from PyQt5 import QtWidgets
+
 from picard import (config, log)
+from picard.ui.options import (
+    OptionsPage, OptionsCheckError,
+    register_options_page
+)
 import picard.util
+
+import sre_constants
 import re
 
 def modulename():
     return modulename.__module__[len("picard.plugins."):]
 
+class UI_TweakFilenameFilter(object):
+    def setupUi(self, TweakFilenameOptionsPage):
+        top = QtWidgets.QVBoxLayout(TweakFilenameOptionsPage)
+
+        group = QtWidgets.QGroupBox(TweakFilenameOptionsPage)
+        group.setTitle("Filename Sanitizer")
+        top.addWidget(group)
+
+        box = QtWidgets.QVBoxLayout(group)
+
+        msg = QtWidgets.QLabel(group)
+        msg.setText('''<em>Picard normally replaces slashes and backslashes
+        with underscores in all metadata tags prior to running the file-naming
+        script.  This substitution may be customized here.  Replacement text
+        may use <a href='https://docs.python.org/3/library/re.html#re.sub'
+        >backslash sequences supported by <code>re.sub</code></a>.</em>''')
+        msg.setOpenExternalLinks(True)
+        box.addWidget(msg)
+
+        self.replace_slashes = QtWidgets.QCheckBox(group)
+        self.replace_slashes.setText("Replace slashes in metadata")
+        self.replace_slashes.setChecked(True)
+        self.replace_slashes.setEnabled(False)
+        box.addWidget(self.replace_slashes)
+
+        self.replace_backslashes = QtWidgets.QCheckBox(group)
+        self.replace_backslashes.setText("Replace backslashes in metadata")
+        box.addWidget(self.replace_backslashes)
+
+        label = QtWidgets.QLabel()
+        label.setText("Replacement text:")
+        box.addWidget(label)
+
+        self.sanitize_replacement = QtWidgets.QLineEdit(group)
+        box.addWidget(self.sanitize_replacement)
+        label.setBuddy(self.sanitize_replacement)
+
+        top.addStretch()
+
+class TweakFilenameOptionsPage(OptionsPage):
+    NAME = PLUGIN_NAME
+    TITLE = PLUGIN_NAME
+    PARENT = None
+    SORT_ORDER = 99
+    ACTIVE = True
+
+    options = [
+        config.TextOption("setting", "tweak_file_replacement_char", "_"),
+        config.BoolOption("setting", "tweak_file_replace_backslash", True)
+    ]
+
+    def __init__(self, parent=None):
+        super().__init__(parent)
+        self.ui = UI_TweakFilenameFilter()
+        self.ui.setupUi(self)
+
+    def load(self):
+        self.ui.replace_backslashes.setChecked(
+            config.setting["tweak_file_replace_backslash"]
+        )
+        self.ui.sanitize_replacement.setText(
+            config.setting["tweak_file_replacement_char"]
+        )
+
+    def check(self):
+        test = SanitizeHook(self.ui.replace_backslashes.isChecked())
+        test.replacement = self.ui.sanitize_replacement.text()
+        try:
+            test.sub("xyzzy", "a/b/c")
+        except sre_constants.error as err:
+            raise OptionsCheckError(_("Error"),
+                                    "Error in substitution: %s" % err);
+
+    def save(self):
+        config.setting["tweak_file_replace_backslash"] = \
+            self.ui.replace_backslashes.isChecked()
+        config.setting["tweak_file_replacement_char"] = \
+            self.ui.sanitize_replacement.text()
+        install_tweaker()
+
 # Hook picard.util.sanitize_filename by replacing the underying re object.
 class SanitizeHook(object):
-    def __init__(self):
-        if config.setting["tweak_file_replace_backslash"]:
+    def __init__(self, bs = config.setting["tweak_file_replace_backslash"]):
+        if bs:
             self.re_match = re.compile(r'[\\/]', re.UNICODE)
         else:
             self.re_match = re.compile(r'[/]', re.UNICODE)
+        self.replacement = config.setting["tweak_file_replacement_char"]
 
     def sub(self, repl, string):
-        ret = self.re_match.sub(
-                 config.setting["tweak_file_replacement_char"],
-                 string)
+        ret = self.re_match.sub(self.replacement, string)
         return ret
 
-
 def install_tweaker():
-    picard.util._re_slashes = SanitizeHook()
-    log.info("%s activated" % (modulename()))
+    re = SanitizeHook()
+    if not hasattr(picard.util, "_re_slashes"):
+        # Harder to globally monkey patch this picard.util function on newer
+        # Picard, so instead we patch it in the two modules which import it.
+        orig_sanitize_filename = picard.util.sanitize_filename
+        def sanitize_filename_hook(string, **kwargs):
+            return orig_sanitize_filename(re.sub(None, string), **kwargs)
 
-config.TextOption("setting", "tweak_file_replacement_char", "_"),
-config.BoolOption("setting", "tweak_file_replace_backslash", True),
+        picard.util.scripttofilename.sanitize_filename = sanitize_filename_hook
+        picard.util.textencoding.sanitize_filename = sanitize_filename_hook
+    else:
+        # On older picard we can monkey patch the underlying re object.
+        picard.util._re_slashes = re
+
+    log.info("%s activated" % (modulename()))
 
 if modulename() in config.setting["enabled_plugins"]:
+    register_options_page(TweakFilenameOptionsPage)
     install_tweaker()
 else:
     log.debug("%s disabled in configuration" % (modulename()))