diff --git a/picard/ui/metadatabox.py b/picard/ui/metadatabox.py
index ae9074672..883717c53 100644
--- a/picard/ui/metadatabox.py
+++ b/picard/ui/metadatabox.py
@@ -96,18 +96,19 @@ class TagCounter(dict):
class TagDiff(object):
- __slots__ = ("tag_names", "new", "orig", "status", "objects")
+ __slots__ = ("tag_names", "new", "orig", "status", "objects", "max_length_delta_ms")
- def __init__(self):
+ def __init__(self, max_length_diff=2):
self.tag_names = []
self.new = TagCounter(self)
self.orig = TagCounter(self)
self.status = defaultdict(lambda: 0)
self.objects = 0
+ self.max_length_delta_ms = max_length_diff * 1000
def __tag_ne(self, tag, orig, new):
if tag == "~length":
- return abs(float(orig) - float(new)) > 2000
+ return abs(float(orig) - float(new)) > self.max_length_delta_ms
else:
return orig != new
@@ -427,7 +428,7 @@ class MetadataBox(QtWidgets.QTableWidget):
if not (files or tracks):
return None
- tag_diff = TagDiff()
+ tag_diff = TagDiff(max_length_diff=config.setting["ignore_track_duration_difference_under"])
orig_tags = tag_diff.orig
new_tags = tag_diff.new
# existing_tags are orig_tags that would not be overwritten by
diff --git a/picard/ui/options/advanced.py b/picard/ui/options/advanced.py
index 4502341f3..fd46b4d06 100644
--- a/picard/ui/options/advanced.py
+++ b/picard/ui/options/advanced.py
@@ -34,6 +34,7 @@ class AdvancedOptionsPage(OptionsPage):
config.TextOption("setting", "ignore_regex", ""),
config.BoolOption("setting", "ignore_hidden_files", False),
config.BoolOption("setting", "recursively_add_files", True),
+ config.IntOption("setting", "ignore_track_duration_difference_under", 2),
config.BoolOption("setting", "completeness_ignore_videos", False),
config.BoolOption("setting", "completeness_ignore_pregap", False),
config.BoolOption("setting", "completeness_ignore_data", False),
@@ -50,6 +51,7 @@ class AdvancedOptionsPage(OptionsPage):
self.ui.ignore_regex.setText(config.setting["ignore_regex"])
self.ui.ignore_hidden_files.setChecked(config.setting["ignore_hidden_files"])
self.ui.recursively_add_files.setChecked(config.setting["recursively_add_files"])
+ self.ui.ignore_track_duration_difference_under.setValue(config.setting["ignore_track_duration_difference_under"])
self.ui.completeness_ignore_videos.setChecked(config.setting["completeness_ignore_videos"])
self.ui.completeness_ignore_pregap.setChecked(config.setting["completeness_ignore_pregap"])
self.ui.completeness_ignore_data.setChecked(config.setting["completeness_ignore_data"])
@@ -59,6 +61,7 @@ class AdvancedOptionsPage(OptionsPage):
config.setting["ignore_regex"] = self.ui.ignore_regex.text()
config.setting["ignore_hidden_files"] = self.ui.ignore_hidden_files.isChecked()
config.setting["recursively_add_files"] = self.ui.recursively_add_files.isChecked()
+ config.setting["ignore_track_duration_difference_under"] = self.ui.ignore_track_duration_difference_under.value()
config.setting["completeness_ignore_videos"] = self.ui.completeness_ignore_videos.isChecked()
config.setting["completeness_ignore_pregap"] = self.ui.completeness_ignore_pregap.isChecked()
config.setting["completeness_ignore_data"] = self.ui.completeness_ignore_data.isChecked()
diff --git a/picard/ui/ui_options_advanced.py b/picard/ui/ui_options_advanced.py
index f094fa872..0148076ac 100644
--- a/picard/ui/ui_options_advanced.py
+++ b/picard/ui/ui_options_advanced.py
@@ -16,22 +16,51 @@ class Ui_AdvancedOptionsPage(object):
self.gridlayout = QtWidgets.QGridLayout(self.groupBox)
self.gridlayout.setSpacing(2)
self.gridlayout.setObjectName("gridlayout")
+ self.recursively_add_files = QtWidgets.QCheckBox(self.groupBox)
+ self.recursively_add_files.setObjectName("recursively_add_files")
+ self.gridlayout.addWidget(self.recursively_add_files, 5, 0, 1, 1)
+ self.horizontalLayout = QtWidgets.QHBoxLayout()
+ self.horizontalLayout.setSizeConstraint(QtWidgets.QLayout.SetDefaultConstraint)
+ self.horizontalLayout.setObjectName("horizontalLayout")
+ self.label_track_duration_diff = QtWidgets.QLabel(self.groupBox)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(self.label_track_duration_diff.sizePolicy().hasHeightForWidth())
+ self.label_track_duration_diff.setSizePolicy(sizePolicy)
+ self.label_track_duration_diff.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
+ self.label_track_duration_diff.setObjectName("label_track_duration_diff")
+ self.horizontalLayout.addWidget(self.label_track_duration_diff)
+ self.ignore_track_duration_difference_under = QtWidgets.QSpinBox(self.groupBox)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(self.ignore_track_duration_difference_under.sizePolicy().hasHeightForWidth())
+ self.ignore_track_duration_difference_under.setSizePolicy(sizePolicy)
+ self.ignore_track_duration_difference_under.setButtonSymbols(QtWidgets.QAbstractSpinBox.UpDownArrows)
+ self.ignore_track_duration_difference_under.setAccelerated(True)
+ self.ignore_track_duration_difference_under.setSuffix("")
+ self.ignore_track_duration_difference_under.setMinimum(1)
+ self.ignore_track_duration_difference_under.setMaximum(7200)
+ self.ignore_track_duration_difference_under.setProperty("value", 2)
+ self.ignore_track_duration_difference_under.setObjectName("ignore_track_duration_difference_under")
+ self.horizontalLayout.addWidget(self.ignore_track_duration_difference_under)
+ spacerItem = QtWidgets.QSpacerItem(4000, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
+ self.horizontalLayout.addItem(spacerItem)
+ self.gridlayout.addLayout(self.horizontalLayout, 6, 0, 2, 1)
+ self.label_ignore_regex = QtWidgets.QLabel(self.groupBox)
+ self.label_ignore_regex.setObjectName("label_ignore_regex")
+ self.gridlayout.addWidget(self.label_ignore_regex, 1, 0, 1, 1)
self.regex_error = QtWidgets.QLabel(self.groupBox)
self.regex_error.setText("")
self.regex_error.setObjectName("regex_error")
self.gridlayout.addWidget(self.regex_error, 3, 0, 1, 1)
- self.label_ignore_regex = QtWidgets.QLabel(self.groupBox)
- self.label_ignore_regex.setObjectName("label_ignore_regex")
- self.gridlayout.addWidget(self.label_ignore_regex, 1, 0, 1, 1)
self.ignore_hidden_files = QtWidgets.QCheckBox(self.groupBox)
self.ignore_hidden_files.setObjectName("ignore_hidden_files")
self.gridlayout.addWidget(self.ignore_hidden_files, 4, 0, 1, 1)
self.ignore_regex = QtWidgets.QLineEdit(self.groupBox)
self.ignore_regex.setObjectName("ignore_regex")
self.gridlayout.addWidget(self.ignore_regex, 2, 0, 1, 1)
- self.recursively_add_files = QtWidgets.QCheckBox(self.groupBox)
- self.recursively_add_files.setObjectName("recursively_add_files")
- self.gridlayout.addWidget(self.recursively_add_files, 5, 0, 1, 1)
self.vboxlayout.addWidget(self.groupBox)
self.groupBox_completeness = QtWidgets.QGroupBox(AdvancedOptionsPage)
self.groupBox_completeness.setObjectName("groupBox_completeness")
@@ -51,18 +80,26 @@ class Ui_AdvancedOptionsPage(object):
self.completeness_ignore_silence.setObjectName("completeness_ignore_silence")
self.verticalLayout_2.addWidget(self.completeness_ignore_silence)
self.vboxlayout.addWidget(self.groupBox_completeness)
- spacerItem = QtWidgets.QSpacerItem(181, 21, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
- self.vboxlayout.addItem(spacerItem)
+ spacerItem1 = QtWidgets.QSpacerItem(181, 21, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
+ self.vboxlayout.addItem(spacerItem1)
self.retranslateUi(AdvancedOptionsPage)
QtCore.QMetaObject.connectSlotsByName(AdvancedOptionsPage)
+ AdvancedOptionsPage.setTabOrder(self.ignore_regex, self.ignore_hidden_files)
+ AdvancedOptionsPage.setTabOrder(self.ignore_hidden_files, self.recursively_add_files)
+ AdvancedOptionsPage.setTabOrder(self.recursively_add_files, self.ignore_track_duration_difference_under)
+ AdvancedOptionsPage.setTabOrder(self.ignore_track_duration_difference_under, self.completeness_ignore_videos)
+ AdvancedOptionsPage.setTabOrder(self.completeness_ignore_videos, self.completeness_ignore_pregap)
+ AdvancedOptionsPage.setTabOrder(self.completeness_ignore_pregap, self.completeness_ignore_data)
+ AdvancedOptionsPage.setTabOrder(self.completeness_ignore_data, self.completeness_ignore_silence)
def retranslateUi(self, AdvancedOptionsPage):
_translate = QtCore.QCoreApplication.translate
self.groupBox.setTitle(_("Advanced options"))
+ self.recursively_add_files.setText(_("Recursively add files and folders from directory"))
+ self.label_track_duration_diff.setText(_("Ignore track duration difference under this number of seconds"))
self.label_ignore_regex.setText(_("Ignore file paths matching the following regular expression:"))
self.ignore_hidden_files.setText(_("Ignore hidden files"))
- self.recursively_add_files.setText(_("Recursively add files and folders from directory"))
self.groupBox_completeness.setTitle(_("Ignore the following tracks when determining whether a release is complete"))
self.completeness_ignore_videos.setText(_("Video tracks"))
self.completeness_ignore_pregap.setText(_("Pregap tracks"))
diff --git a/ui/options_advanced.ui b/ui/options_advanced.ui
index 2438d0f95..7c146efd0 100644
--- a/ui/options_advanced.ui
+++ b/ui/options_advanced.ui
@@ -20,13 +20,80 @@
2
- -
-
+
-
+
-
+ Recursively add files and folders from directory
+ -
+
+
+ QLayout::SetDefaultConstraint
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ Ignore track duration difference under this number of seconds
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ QAbstractSpinBox::UpDownArrows
+
+
+ true
+
+
+
+
+
+ 1
+
+
+ 7200
+
+
+ 2
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QSizePolicy::Expanding
+
+
+
+ 4000
+ 20
+
+
+
+
+
+
-
@@ -34,6 +101,13 @@
+ -
+
+
+
+
+
+
-
@@ -44,13 +118,6 @@
-
- -
-
-
- Recursively add files and folders from directory
-
-
-
@@ -111,6 +178,13 @@
ignore_regex
+ ignore_hidden_files
+ recursively_add_files
+ ignore_track_duration_difference_under
+ completeness_ignore_videos
+ completeness_ignore_pregap
+ completeness_ignore_data
+ completeness_ignore_silence