From c99aba714cf6166e719a2dab17205f8b54f1cc71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Lalinsk=C3=BD?= Date: Sun, 10 Apr 2011 19:34:50 +0200 Subject: [PATCH] Add an option to replace Unicode punctuation --- picard/album.py | 11 ++- picard/metadata.py | 13 +-- picard/ui/options/metadata.py | 3 + picard/ui/ui_options_metadata.py | 90 +++++++++------------ picard/util/__init__.py | 27 +++++++ ui/options_metadata.ui | 131 +++++++++++++++---------------- 6 files changed, 150 insertions(+), 125 deletions(-) diff --git a/picard/album.py b/picard/album.py index 06d9ace43..68de27dcd 100644 --- a/picard/album.py +++ b/picard/album.py @@ -26,7 +26,7 @@ from picard.file import File from picard.track import Track from picard.script import ScriptParser from picard.ui.item import Item -from picard.util import format_time, partial, translate_artist, queue +from picard.util import format_time, partial, translate_artist, queue, asciipunct from picard.cluster import Cluster from picard.mbxml import release_to_metadata, track_to_metadata @@ -246,6 +246,10 @@ class Album(DataObject, Item): if self.config.setting['folksonomy_tags']: self._convert_folksonomy_tags_to_genre(t, ignore_tags) + # Convert Unicode punctuation + if self.config.setting['convert_punctuation']: + tm.apply_func(asciipunct) + # Track metadata plugins try: run_track_metadata_processors(self, tm, release_node, node) @@ -265,6 +269,9 @@ class Album(DataObject, Item): self.log.error(traceback.format_exc()) # Strip leading/trailing whitespace track.metadata.strip_whitespace() + # Convert Unicode punctuation + if self.config.setting['convert_punctuation']: + track.metadat.apply_func(asciipunct) # Run tagger script for release events for rel in self.release_events: @@ -276,7 +283,7 @@ class Album(DataObject, Item): rel.from_metadata(temp_metadata) except: self.log.error(traceback.format_exc()) - + # Run tagger script for the album itself try: parser.eval(script, m) diff --git a/picard/metadata.py b/picard/metadata.py index f0b8b3082..88e9e12df 100644 --- a/picard/metadata.py +++ b/picard/metadata.py @@ -174,6 +174,13 @@ class Metadata(object): def set_changed(self, changed=True): self.changed = changed + def apply_func(self, func): + new = Metadata() + for key, values in self.rawitems(): + if not key.startswith("~"): + new[key] = map(func, values) + self.update(new) + def strip_whitespace(self): """Strip leading/trailing whitespace. @@ -185,11 +192,7 @@ class Metadata(object): >>> m["foo"] "bar" """ - new = Metadata() - for key, values in self.rawitems(): - if not key.startswith("~"): - new[key] = [value.strip() for value in values] - self.update(new) + self.apply_func(lambda s: s.strip()) _album_metadata_processors = ExtensionPoint() diff --git a/picard/ui/options/metadata.py b/picard/ui/options/metadata.py index 95ec922c8..71a9c8cce 100644 --- a/picard/ui/options/metadata.py +++ b/picard/ui/options/metadata.py @@ -42,6 +42,7 @@ class MetadataOptionsPage(OptionsPage): BoolOption("setting", "track_ars", False), BoolOption("setting", "folksonomy_tags", False), TextOption("setting", "preferred_release_country", u""), + BoolOption("setting", "convert_punctuation", False), ] def __init__(self, parent=None): @@ -58,6 +59,7 @@ class MetadataOptionsPage(OptionsPage): def load(self): self.ui.translate_artist_names.setChecked(self.config.setting["translate_artist_names"]) + self.ui.convert_punctuation.setChecked(self.config.setting["convert_punctuation"]) self.ui.release_ars.setChecked(self.config.setting["release_ars"]) self.ui.track_ars.setChecked(self.config.setting["track_ars"]) self.ui.folksonomy_tags.setChecked(self.config.setting["folksonomy_tags"]) @@ -68,6 +70,7 @@ class MetadataOptionsPage(OptionsPage): def save(self): self.config.setting["translate_artist_names"] = self.ui.translate_artist_names.isChecked() + self.config.setting["convert_punctuation"] = self.ui.convert_punctuation.isChecked() self.config.setting["release_ars"] = self.ui.release_ars.isChecked() self.config.setting["track_ars"] = self.ui.track_ars.isChecked() self.config.setting["folksonomy_tags"] = self.ui.folksonomy_tags.isChecked() diff --git a/picard/ui/ui_options_metadata.py b/picard/ui/ui_options_metadata.py index 90037767f..bcb2de330 100644 --- a/picard/ui/ui_options_metadata.py +++ b/picard/ui/ui_options_metadata.py @@ -2,8 +2,8 @@ # Form implementation generated from reading ui file 'ui/options_metadata.ui' # -# Created: Wed Apr 2 08:48:11 2008 -# by: PyQt4 UI code generator 4.3 +# Created: Sun Apr 10 19:32:51 2011 +# by: PyQt4 UI code generator 4.7.4 # # WARNING! All changes made in this file will be lost! @@ -12,93 +12,79 @@ from PyQt4 import QtCore, QtGui class Ui_MetadataOptionsPage(object): def setupUi(self, MetadataOptionsPage): MetadataOptionsPage.setObjectName("MetadataOptionsPage") - MetadataOptionsPage.resize(QtCore.QSize(QtCore.QRect(0,0,387,355).size()).expandedTo(MetadataOptionsPage.minimumSizeHint())) - - self.vboxlayout = QtGui.QVBoxLayout(MetadataOptionsPage) - self.vboxlayout.setObjectName("vboxlayout") - + MetadataOptionsPage.resize(403, 445) + self.verticalLayout = QtGui.QVBoxLayout(MetadataOptionsPage) + self.verticalLayout.setObjectName("verticalLayout") self.rename_files = QtGui.QGroupBox(MetadataOptionsPage) self.rename_files.setObjectName("rename_files") - - self.gridlayout = QtGui.QGridLayout(self.rename_files) - self.gridlayout.setObjectName("gridlayout") - + self.gridLayout = QtGui.QGridLayout(self.rename_files) + self.gridLayout.setSpacing(2) + self.gridLayout.setObjectName("gridLayout") self.translate_artist_names = QtGui.QCheckBox(self.rename_files) self.translate_artist_names.setObjectName("translate_artist_names") - self.gridlayout.addWidget(self.translate_artist_names,0,0,1,2) - + self.gridLayout.addWidget(self.translate_artist_names, 0, 0, 1, 2) + self.convert_punctuation = QtGui.QCheckBox(self.rename_files) + self.convert_punctuation.setObjectName("convert_punctuation") + self.gridLayout.addWidget(self.convert_punctuation, 1, 0, 1, 2) self.release_ars = QtGui.QCheckBox(self.rename_files) self.release_ars.setObjectName("release_ars") - self.gridlayout.addWidget(self.release_ars,1,0,1,2) - + self.gridLayout.addWidget(self.release_ars, 2, 0, 1, 2) self.track_ars = QtGui.QCheckBox(self.rename_files) self.track_ars.setObjectName("track_ars") - self.gridlayout.addWidget(self.track_ars,2,0,1,2) - + self.gridLayout.addWidget(self.track_ars, 3, 0, 1, 2) self.folksonomy_tags = QtGui.QCheckBox(self.rename_files) self.folksonomy_tags.setObjectName("folksonomy_tags") - self.gridlayout.addWidget(self.folksonomy_tags,3,0,1,2) - + self.gridLayout.addWidget(self.folksonomy_tags, 4, 0, 1, 2) self.label = QtGui.QLabel(self.rename_files) self.label.setObjectName("label") - self.gridlayout.addWidget(self.label,4,0,1,2) - + self.gridLayout.addWidget(self.label, 5, 0, 1, 2) self.preferred_release_country = QtGui.QComboBox(self.rename_files) self.preferred_release_country.setObjectName("preferred_release_country") - self.gridlayout.addWidget(self.preferred_release_country,5,0,1,1) - - spacerItem = QtGui.QSpacerItem(161,20,QtGui.QSizePolicy.Expanding,QtGui.QSizePolicy.Minimum) - self.gridlayout.addItem(spacerItem,5,1,1,1) - self.vboxlayout.addWidget(self.rename_files) - + self.gridLayout.addWidget(self.preferred_release_country, 6, 0, 1, 1) + spacerItem = QtGui.QSpacerItem(161, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) + self.gridLayout.addItem(spacerItem, 6, 1, 1, 1) + self.verticalLayout.addWidget(self.rename_files) self.rename_files_2 = QtGui.QGroupBox(MetadataOptionsPage) self.rename_files_2.setObjectName("rename_files_2") - - self.gridlayout1 = QtGui.QGridLayout(self.rename_files_2) - self.gridlayout1.setMargin(9) - self.gridlayout1.setSpacing(2) - self.gridlayout1.setObjectName("gridlayout1") - + self.gridlayout = QtGui.QGridLayout(self.rename_files_2) + self.gridlayout.setMargin(9) + self.gridlayout.setSpacing(2) + self.gridlayout.setObjectName("gridlayout") self.label_3 = QtGui.QLabel(self.rename_files_2) self.label_3.setObjectName("label_3") - self.gridlayout1.addWidget(self.label_3,0,0,1,2) - + self.gridlayout.addWidget(self.label_3, 0, 0, 1, 2) self.label_4 = QtGui.QLabel(self.rename_files_2) self.label_4.setObjectName("label_4") - self.gridlayout1.addWidget(self.label_4,2,0,1,2) - + self.gridlayout.addWidget(self.label_4, 2, 0, 1, 2) self.nat_name = QtGui.QLineEdit(self.rename_files_2) self.nat_name.setObjectName("nat_name") - self.gridlayout1.addWidget(self.nat_name,3,0,1,1) - + self.gridlayout.addWidget(self.nat_name, 3, 0, 1, 1) self.nat_name_default = QtGui.QPushButton(self.rename_files_2) self.nat_name_default.setObjectName("nat_name_default") - self.gridlayout1.addWidget(self.nat_name_default,3,1,1,1) - + self.gridlayout.addWidget(self.nat_name_default, 3, 1, 1, 1) self.va_name_default = QtGui.QPushButton(self.rename_files_2) self.va_name_default.setObjectName("va_name_default") - self.gridlayout1.addWidget(self.va_name_default,1,1,1,1) - + self.gridlayout.addWidget(self.va_name_default, 1, 1, 1, 1) self.va_name = QtGui.QLineEdit(self.rename_files_2) self.va_name.setObjectName("va_name") - self.gridlayout1.addWidget(self.va_name,1,0,1,1) - self.vboxlayout.addWidget(self.rename_files_2) - - spacerItem1 = QtGui.QSpacerItem(261,16,QtGui.QSizePolicy.Minimum,QtGui.QSizePolicy.Expanding) - self.vboxlayout.addItem(spacerItem1) + self.gridlayout.addWidget(self.va_name, 1, 0, 1, 1) + self.verticalLayout.addWidget(self.rename_files_2) + spacerItem1 = QtGui.QSpacerItem(261, 16, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) + self.verticalLayout.addItem(spacerItem1) self.label_3.setBuddy(self.va_name_default) self.label_4.setBuddy(self.nat_name_default) self.retranslateUi(MetadataOptionsPage) QtCore.QMetaObject.connectSlotsByName(MetadataOptionsPage) - MetadataOptionsPage.setTabOrder(self.translate_artist_names,self.va_name) - MetadataOptionsPage.setTabOrder(self.va_name,self.va_name_default) - MetadataOptionsPage.setTabOrder(self.va_name_default,self.nat_name) - MetadataOptionsPage.setTabOrder(self.nat_name,self.nat_name_default) + MetadataOptionsPage.setTabOrder(self.translate_artist_names, self.va_name) + MetadataOptionsPage.setTabOrder(self.va_name, self.va_name_default) + MetadataOptionsPage.setTabOrder(self.va_name_default, self.nat_name) + MetadataOptionsPage.setTabOrder(self.nat_name, self.nat_name_default) def retranslateUi(self, MetadataOptionsPage): self.rename_files.setTitle(_("Metadata")) self.translate_artist_names.setText(_("Translate foreign artist names to English where possible")) + self.convert_punctuation.setText(_("Convert Unicode punctuation characters to ASCII")) self.release_ars.setText(_("Use release relationships")) self.track_ars.setText(_("Use track relationships")) self.folksonomy_tags.setText(_("Use folksonomy tags as genre")) diff --git a/picard/util/__init__.py b/picard/util/__init__.py index 6a5b5f20e..9169688cb 100644 --- a/picard/util/__init__.py +++ b/picard/util/__init__.py @@ -27,6 +27,33 @@ from encodings import rot_13; from string import Template +def asciipunct(s): + mapping = { + u"…": u"...", + u"‘": u"'", + u"’": u"'", + u"‚": u"'", + u"“": u"\"", + u"”": u"\"", + u"„": u"\"", + u"′": u"'", + u"″": u"\"", + u"‹": u"<", + u"›": u">", + u"«": u"<<", + u"»": u">>", + u"‐": u"-", + u"‒": u"-", + u"–": u"-", + u"−": u"-", + u"—": u"-", + u"―": u"--", + } + for orig, repl in mapping.iteritems(): + s = s.replace(orig, repl) + return s + + def needs_read_lock(func): """Adds a read lock around ``func``. diff --git a/ui/options_metadata.ui b/ui/options_metadata.ui index 2d9c66999..581ef583b 100644 --- a/ui/options_metadata.ui +++ b/ui/options_metadata.ui @@ -1,65 +1,76 @@ - + + MetadataOptionsPage - - + + 0 0 - 387 - 355 + 403 + 445 - + - - + + Metadata - - - - + + + 2 + + + + Translate foreign artist names to English where possible - - - + + + + Convert Unicode punctuation characters to ASCII + + + + + + Use release relationships - - - + + + Use track relationships - - - + + + Use folksonomy tags as genre - - - + + + Preferred release country: - - + + - + - + Qt::Horizontal - + 161 20 @@ -71,78 +82,66 @@ - - + + Custom Fields - - + + 9 - - 9 - - - 9 - - - 9 - - + 2 - - 2 - - - - + + + Various artists: - + va_name_default - - - + + + Non-album tracks: - + nat_name_default - - + + - - - + + + Default - - - + + + Default - - + + - + Qt::Vertical - + 261 16