use thefuzz

use thefuzz

use thefuzz
This commit is contained in:
Timmy Welch 2022-07-08 12:33:00 -07:00
parent c0880c9afe
commit 947dc81c74
13 changed files with 200 additions and 181 deletions

View File

@ -26,6 +26,7 @@ from shutil import which # noqa: F401
from typing import Any, Mapping
import pycountry
import thefuzz.fuzz
logger = logging.getLogger(__name__)
@ -108,6 +109,10 @@ def remove_articles(text: str) -> str:
"the",
"the",
"with",
"ms",
"mrs",
"mr",
"dr",
]
new_text = ""
for word in text.split(" "):
@ -142,13 +147,18 @@ def sanitize_title(text: str, basic: bool = False) -> str:
return text
def titles_match(search_title, record_title):
def titles_match(search_title: str, record_title: str, threshold: int = 90):
sanitized_search = sanitize_title(search_title)
sanitized_record = sanitize_title(record_title)
for term in sanitized_search.split():
if term not in sanitized_record:
return False
return True
ratio = thefuzz.fuzz.ratio(sanitized_search, sanitized_record)
logger.debug(
"search title: %s ; record title: %s ; ratio: %d ; match threshold: %d",
search_title,
record_title,
ratio,
threshold,
)
return ratio >= threshold
def unique_file(file_name: pathlib.Path) -> pathlib.Path:

View File

@ -17,7 +17,7 @@ from __future__ import annotations
import logging
from PyQt5 import QtCore, QtGui, QtWidgets, uic
from PyQt5 import QtCore, QtWidgets, uic
from comictaggerlib.settings import ComicTaggerSettings
@ -39,7 +39,7 @@ class AutoTagStartWindow(QtWidgets.QDialog):
self.cbxSpecifySearchString.setChecked(False)
self.cbxSplitWords.setChecked(False)
self.leNameLengthMatchTolerance.setText(str(self.settings.id_length_delta_thresh))
self.sbNameMatchSearchThresh.setValue(self.settings.id_series_match_identify_thresh)
self.leSearchString.setEnabled(False)
self.cbxSaveOnLowConfidence.setChecked(self.settings.save_on_low_confidence)
@ -50,13 +50,12 @@ class AutoTagStartWindow(QtWidgets.QDialog):
self.cbxWaitForRateLimit.setChecked(self.settings.wait_and_retry_on_rate_limit)
self.cbxAutoImprint.setChecked(self.settings.auto_imprint)
nlmt_tip = """ <html>The <b>Name Length Match Tolerance</b> is for eliminating automatic
search matches that are too long compared to your series name search. The higher
nlmt_tip = """<html>The <b>Name Match Ratio Threshold: Auto-Identify</b> is for eliminating automatic
search matches that are too long compared to your series name search. The lower
it is, the more likely to have a good match, but each search will take longer and
use more bandwidth. Too low, and only the very closest lexical matches will be
explored.</html>"""
use more bandwidth. Too high, and only the very closest matches will be explored.</html>"""
self.leNameLengthMatchTolerance.setToolTip(nlmt_tip)
self.sbNameMatchSearchThresh.setToolTip(nlmt_tip)
ss_tip = """<html>
The <b>series search string</b> specifies the search string to be used for all selected archives.
@ -66,9 +65,6 @@ class AutoTagStartWindow(QtWidgets.QDialog):
self.leSearchString.setToolTip(ss_tip)
self.cbxSpecifySearchString.setToolTip(ss_tip)
validator = QtGui.QIntValidator(0, 99, self)
self.leNameLengthMatchTolerance.setValidator(validator)
self.cbxSpecifySearchString.stateChanged.connect(self.search_string_toggle)
self.auto_save_on_low = False
@ -78,7 +74,7 @@ class AutoTagStartWindow(QtWidgets.QDialog):
self.remove_after_success = False
self.wait_and_retry_on_rate_limit = False
self.search_string = ""
self.name_length_match_tolerance = self.settings.id_length_delta_thresh
self.name_length_match_tolerance = self.settings.id_series_match_search_thresh
self.split_words = self.cbxSplitWords.isChecked()
def search_string_toggle(self) -> None:
@ -93,7 +89,7 @@ class AutoTagStartWindow(QtWidgets.QDialog):
self.assume_issue_one = self.cbxAssumeIssueOne.isChecked()
self.ignore_leading_digits_in_filename = self.cbxIgnoreLeadingDigitsInFilename.isChecked()
self.remove_after_success = self.cbxRemoveAfterSuccess.isChecked()
self.name_length_match_tolerance = int(self.leNameLengthMatchTolerance.text())
self.name_length_match_tolerance = int(self.leNameMatchThresh.text())
self.wait_and_retry_on_rate_limit = self.cbxWaitForRateLimit.isChecked()
self.split_words = self.cbxSplitWords.isChecked()

View File

@ -42,7 +42,7 @@ def actual_issue_data_fetch(
) -> GenericMetadata:
# now get the particular issue data
try:
comic_vine = ComicVineTalker()
comic_vine = ComicVineTalker(settings.id_series_match_search_thresh)
comic_vine.wait_for_rate_limit = opts.wait_on_cv_rate_limit
cv_md = comic_vine.fetch_issue_data(match["volume_id"], match["issue_number"], settings)
except ComicVineTalkerException:
@ -375,7 +375,7 @@ def process_file_cli(
if opts.issue_id is not None:
# we were given the actual ID to search with
try:
comic_vine = ComicVineTalker()
comic_vine = ComicVineTalker(settings.id_series_match_search_thresh)
comic_vine.wait_for_rate_limit = opts.wait_on_cv_rate_limit
cv_md = comic_vine.fetch_issue_data_by_issue_id(opts.issue_id, settings)
except ComicVineTalkerException:

View File

@ -91,11 +91,12 @@ class ComicVineTalker:
return "Comic Vine rate limit exceeded. Please wait a bit."
def __init__(self) -> None:
def __init__(self, series_match_thresh: int = 90) -> None:
# Identity name for the information source
self.source_name = "comicvine"
self.wait_for_rate_limit = False
self.series_match_thresh = series_match_thresh
# key that is registered to comictagger
default_api_key = "27431e6787042105bd3e47e169a624521f89f3a4"
@ -245,10 +246,8 @@ class ComicVineTalker:
# ORed together, and we get thousands of results. Good news is the
# results are sorted by relevance, so we can be smart about halting the search.
# 1. Don't fetch more than some sane amount of pages.
max_results = 500
# 2. Halt when not all of our search terms are present in a result
# 3. Halt when the results contain more (plus threshold) words than our search
result_word_count_max = len(search_series_name.split()) + 3
# 2. Halt when any result on the current page is less than or equal to a set ratio using thefuzz
max_results = 500 # 5 pages
total_result_count = min(total_result_count, max_results)
@ -267,16 +266,11 @@ class ComicVineTalker:
while current_result_count < total_result_count:
if not literal:
# Sanitize the series name for comicvine searching, comicvine search ignore symbols
last_result = utils.sanitize_title(search_results[-1]["name"])
# See if the last result's name has all the of the search terms.
# If not, break out of this, loop, we're done.
stop_searching = utils.titles_match(search_series_name, last_result)
# Also, stop searching when the word count of last results is too much longer than our search terms list
if len(last_result) > result_word_count_max:
stop_searching = True
# Stop searching once any entry falls below the threshold
stop_searching = any(
not utils.titles_match(search_series_name, volume["name"], self.series_match_thresh)
for volume in cast(list[CVVolumeResults], cv_response["results"])
)
if stop_searching:
break
@ -294,23 +288,6 @@ class ComicVineTalker:
if callback is not None:
callback(current_result_count, total_result_count)
# Literal searches simply return the matches no extra processing is doneo
if not literal:
# Remove any search results that don't contain all the search terms (iterate backwards for easy removal)
for record in reversed(search_results):
matched = False
aliases = []
if record["aliases"]:
aliases = record["aliases"].split("\n")
aliases.append(record["name"])
for name in aliases:
if utils.titles_match(search_series_name, name):
matched = True
break
if not matched:
search_results.remove(record)
# Cache these search results, even if it's literal we cache the results
# The most it will cause is extra processing time
cvc.add_search_results(self.source_name, series_name, search_results)

View File

@ -95,7 +95,7 @@ class IssueIdentifier:
# used to eliminate series names that are too long based on our search
# string
self.length_delta_thresh = settings.id_length_delta_thresh
self.series_match_thresh = settings.id_series_match_identify_thresh
# used to eliminate unlikely publishers
self.publisher_filter = [s.strip().casefold() for s in settings.id_publisher_filter.split(",")]
@ -120,8 +120,8 @@ class IssueIdentifier:
def set_additional_metadata(self, md: GenericMetadata) -> None:
self.additional_metadata = md
def set_name_length_delta_threshold(self, delta: int) -> None:
self.length_delta_thresh = delta
def set_name_series_match_threshold(self, delta: int) -> None:
self.series_match_thresh = delta
def set_publisher_filter(self, flt: list[str]) -> None:
self.publisher_filter = flt
@ -398,7 +398,7 @@ class IssueIdentifier:
if keys["month"] is not None:
self.log_msg("\tMonth: " + str(keys["month"]))
comic_vine = ComicVineTalker()
comic_vine = ComicVineTalker(self.settings.id_series_match_search_thresh)
comic_vine.wait_for_rate_limit = self.wait_and_retry_on_rate_limit
comic_vine.set_log_func(self.output_function)
@ -433,15 +433,13 @@ class IssueIdentifier:
if int(keys["year"]) < int(item["start_year"]):
date_approved = False
# assume that our search name is close to the actual name, say
# within ,e.g. 5 chars
# sanitize both the search string and the result so that
# we are comparing the same type of data
shortened_key = utils.sanitize_title(keys["series"])
shortened_item_name = utils.sanitize_title(item["name"])
if len(shortened_item_name) < (len(shortened_key) + self.length_delta_thresh):
length_approved = True
aliases = []
if item["aliases"]:
aliases = item["aliases"].split("\n")
for name in [item["name"], *aliases]:
if utils.titles_match(keys["series"], name, self.series_match_thresh):
length_approved = True
break
# remove any series from publishers on the filter
if item["publisher"] is not None:
publisher = item["publisher"]["name"]

View File

@ -97,7 +97,7 @@ class IssueSelectionWindow(QtWidgets.QDialog):
QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.CursorShape.WaitCursor))
try:
comic_vine = ComicVineTalker()
comic_vine = ComicVineTalker(self.settings.id_series_match_search_thresh)
comic_vine.fetch_volume_data(self.series_id)
self.issue_list = comic_vine.fetch_issues_by_volume(self.series_id)
except ComicVineTalkerException as e:

View File

@ -78,7 +78,8 @@ class ComicTaggerSettings:
self.last_filelist_sorted_order = 0
# identifier settings
self.id_length_delta_thresh = 5
self.id_series_match_search_thresh = 90
self.id_series_match_identify_thresh = 91
self.id_publisher_filter = "Panini Comics, Abril, Planeta DeAgostini, Editorial Televisa, Dino Comics"
# Show/ask dialog flags
@ -217,8 +218,10 @@ class ComicTaggerSettings:
if self.config.has_option("auto", "last_filelist_sorted_order"):
self.last_filelist_sorted_order = self.config.getint("auto", "last_filelist_sorted_order")
if self.config.has_option("identifier", "id_length_delta_thresh"):
self.id_length_delta_thresh = self.config.getint("identifier", "id_length_delta_thresh")
if self.config.has_option("identifier", "id_series_match_search_thresh"):
self.id_series_match_search_thresh = self.config.getint("identifier", "id_series_match_search_thresh")
if self.config.has_option("identifier", "id_series_match_identify_thresh"):
self.id_series_match_identify_thresh = self.config.getint("identifier", "id_series_match_identify_thresh")
if self.config.has_option("identifier", "id_publisher_filter"):
self.id_publisher_filter = self.config.get("identifier", "id_publisher_filter")
@ -352,7 +355,8 @@ class ComicTaggerSettings:
if not self.config.has_section("identifier"):
self.config.add_section("identifier")
self.config.set("identifier", "id_length_delta_thresh", self.id_length_delta_thresh)
self.config.set("identifier", "id_series_match_search_thresh", self.id_series_match_search_thresh)
self.config.set("identifier", "id_series_match_identify_thresh", self.id_series_match_identify_thresh)
self.config.set("identifier", "id_publisher_filter", self.id_publisher_filter)
if not self.config.has_section("dialogflags"):

View File

@ -155,13 +155,16 @@ class SettingsWindow(QtWidgets.QDialog):
self.lblDefaultSettings.setText("Revert to default " + self.name.casefold())
self.btnResetSettings.setText("Default " + self.name)
nldt_tip = """<html>The <b>Default Name Length Match Tolerance</b> is for eliminating automatic
search matches that are too long compared to your series name search. The higher
nmit_tip = """<html>The <b>Name Match Ratio Threshold: Auto-Identify</b> is for eliminating automatic
search matches that are too long compared to your series name search. The lower
it is, the more likely to have a good match, but each search will take longer and
use more bandwidth. Too low, and only the very closest lexical matches will be
explored.</html>"""
use more bandwidth. Too high, and only the very closest matches will be explored.</html>"""
nmst_tip = """<html>The <b>Name Match Ratio Threshold: Search</b> is for reducing the total
number of results that are returned from a search. The lower it is, the more pages will
be returned (max 5 pages or 500 results)</html>"""
self.leNameLengthDeltaThresh.setToolTip(nldt_tip)
self.sbNameMatchIdentifyThresh.setToolTip(nmit_tip)
self.sbNameMatchSearchThresh.setToolTip(nmst_tip)
pbl_tip = """<html>
The <b>Publisher Filter</b> is for eliminating automatic matches to certain publishers
@ -173,9 +176,6 @@ class SettingsWindow(QtWidgets.QDialog):
validator = QtGui.QIntValidator(1, 4, self)
self.leIssueNumPadding.setValidator(validator)
validator = QtGui.QIntValidator(0, 99, self)
self.leNameLengthDeltaThresh.setValidator(validator)
self.leRenameTemplate.setToolTip(f"<pre>{html.escape(template_tooltip)}</pre>")
self.settings_to_form()
self.rename_error: Exception | None = None
@ -225,7 +225,8 @@ class SettingsWindow(QtWidgets.QDialog):
def settings_to_form(self) -> None:
# Copy values from settings to form
self.leRarExePath.setText(self.settings.rar_exe_path)
self.leNameLengthDeltaThresh.setText(str(self.settings.id_length_delta_thresh))
self.sbNameMatchIdentifyThresh.setValue(self.settings.id_series_match_identify_thresh)
self.sbNameMatchSearchThresh.setValue(self.settings.id_series_match_search_thresh)
self.tePublisherFilter.setPlainText(self.settings.id_publisher_filter)
self.cbxCheckForNewVersion.setChecked(self.settings.check_for_new_version)
@ -287,15 +288,13 @@ class SettingsWindow(QtWidgets.QDialog):
if self.settings.rar_exe_path:
utils.add_to_path(os.path.dirname(self.settings.rar_exe_path))
if not str(self.leNameLengthDeltaThresh.text()).isdigit():
self.leNameLengthDeltaThresh.setText("0")
if not str(self.leIssueNumPadding.text()).isdigit():
self.leIssueNumPadding.setText("0")
self.settings.check_for_new_version = self.cbxCheckForNewVersion.isChecked()
self.settings.id_length_delta_thresh = int(self.leNameLengthDeltaThresh.text())
self.settings.id_series_match_identify_thresh = self.sbNameMatchIdentifyThresh.value()
self.settings.id_series_match_search_thresh = self.sbNameMatchSearchThresh.value()
self.settings.id_publisher_filter = str(self.tePublisherFilter.toPlainText())
self.settings.complicated_parser = self.cbxComplicatedParser.isChecked()

View File

@ -1064,7 +1064,7 @@ Have fun!
self.form_to_metadata()
try:
comic_vine = ComicVineTalker()
comic_vine = ComicVineTalker(self.settings.id_series_match_search_thresh)
new_metadata = comic_vine.fetch_issue_data(selector.volume_id, selector.issue_number, self.settings)
except ComicVineTalkerException as e:
QtWidgets.QApplication.restoreOverrideCursor()
@ -1674,7 +1674,7 @@ Have fun!
QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.CursorShape.WaitCursor))
try:
comic_vine = ComicVineTalker()
comic_vine = ComicVineTalker(self.settings.id_series_match_search_thresh)
comic_vine.wait_for_rate_limit = self.settings.wait_and_retry_on_rate_limit
cv_md = comic_vine.fetch_issue_data(match["volume_id"], match["issue_number"], self.settings)
except ComicVineTalkerException:
@ -1743,7 +1743,7 @@ Have fun!
ii.cover_page_index = md.get_cover_page_index_list()[0]
if self.atprogdialog is not None:
ii.set_cover_url_callback(self.atprogdialog.set_test_image)
ii.set_name_length_delta_threshold(dlg.name_length_match_tolerance)
ii.set_name_series_match_threshold(dlg.name_length_match_tolerance)
matches: list[IssueResult] = ii.search()

View File

@ -44,6 +44,16 @@
</item>
<item row="1" column="0">
<layout class="QGridLayout" name="gridLayout">
<item row="6" column="0">
<widget class="QCheckBox" name="cbxAutoImprint">
<property name="toolTip">
<string>Checks the publisher against a list of imprints.</string>
</property>
<property name="text">
<string>Auto Imprint</string>
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QCheckBox" name="cbxSpecifySearchString">
<property name="sizePolicy">
@ -57,19 +67,6 @@
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QCheckBox" name="cbxSaveOnLowConfidence">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Save on low confidence match</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="cbxIgnoreLeadingDigitsInFilename">
<property name="sizePolicy">
@ -83,8 +80,8 @@
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QCheckBox" name="cbxRemoveAfterSuccess">
<item row="0" column="0">
<widget class="QCheckBox" name="cbxSaveOnLowConfidence">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
@ -92,14 +89,43 @@
</sizepolicy>
</property>
<property name="text">
<string>Remove archives from list after successful tagging</string>
<string>Save on low confidence match</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="cbxWaitForRateLimit">
<item row="10" column="0">
<widget class="QLineEdit" name="leSearchString">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="11" column="0">
<widget class="QLabel" name="label_3">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Wait and retry when Comic Vine rate limit is exceeded (experimental)</string>
<string>Adjust Name Match Ratio Threshold: Auto-Identify</string>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QCheckBox" name="cbxSplitWords">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Split words in filenames (e.g. 'judgedredd' to 'judge dredd') (Experimental)</string>
</property>
</widget>
</item>
@ -129,16 +155,6 @@
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QCheckBox" name="cbxAutoImprint">
<property name="toolTip">
<string>Checks the publisher against a list of imprints.</string>
</property>
<property name="text">
<string>Auto Imprint</string>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QCheckBox" name="cbxRemoveMetadata">
<property name="toolTip">
@ -149,8 +165,8 @@
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QCheckBox" name="cbxSplitWords">
<item row="5" column="0">
<widget class="QCheckBox" name="cbxRemoveAfterSuccess">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
@ -158,46 +174,33 @@
</sizepolicy>
</property>
<property name="text">
<string>Split words in filenames (e.g. 'judgedredd' to 'judge dredd') (Experimental)</string>
<string>Remove archives from list after successful tagging</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="cbxWaitForRateLimit">
<property name="text">
<string>Wait and retry when Comic Vine rate limit is exceeded (experimental)</string>
</property>
</widget>
</item>
<item row="12" column="0">
<widget class="QLineEdit" name="leNameLengthMatchTolerance">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<widget class="QSpinBox" name="sbNameMatchSearchThresh">
<property name="maximumSize">
<size>
<width>50</width>
<width>60</width>
<height>16777215</height>
</size>
</property>
</widget>
</item>
<item row="10" column="0">
<widget class="QLineEdit" name="leSearchString">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
<property name="suffix">
<string>%</string>
</property>
</widget>
</item>
<item row="11" column="0">
<widget class="QLabel" name="label_3">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
<property name="minimum">
<number>1</number>
</property>
<property name="text">
<string>Adjust Name Length Match Tolerance:</string>
<property name="maximum">
<number>100</number>
</property>
</widget>
</item>

View File

@ -139,7 +139,7 @@
<item row="0" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;These settings are for the automatic issue identifier which searches online for matches. They will not affect &amp;quot;manual&amp;quot; searching.&lt;/p&gt;&lt;p&gt;Hover the mouse over an entry field for more info.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;These settings are for the automatic issue identifier which searches online for matches. &lt;/p&gt;&lt;p&gt;Hover the mouse over an entry field for more info.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="wordWrap">
<bool>true</bool>
@ -164,47 +164,28 @@
<string/>
</property>
<property name="text">
<string>Default Name Length Match Tolerance:</string>
<string>Default Name Match Ratio Threshold: Search:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="leNameLengthDeltaThresh">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
<item row="1" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Default Name Match Ratio Threshold: Auto-Identify:</string>
</property>
<property name="maximumSize">
<size>
<width>50</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string/>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_4">
<widget class="QLabel" name="label_9">
<property name="text">
<string>Publisher Filter:</string>
<string>Always use Publisher Filter on &quot;manual&quot; searches:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QPlainTextEdit" name="tePublisherFilter">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="cbxUseFilter">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Applies the &lt;span style=&quot; font-weight:600;&quot;&gt;Publisher Filter&lt;/span&gt; on all searches.&lt;br/&gt;The search window has a dynamic toggle to show the unfiltered results.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
@ -214,10 +195,58 @@
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_9">
<item row="3" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Always use Publisher Filter on &quot;manual&quot; searches:</string>
<string>Publisher Filter:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QPlainTextEdit" name="tePublisherFilter">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="sbNameMatchSearchThresh">
<property name="maximumSize">
<size>
<width>60</width>
<height>16777215</height>
</size>
</property>
<property name="suffix">
<string>%</string>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>100</number>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="sbNameMatchIdentifyThresh">
<property name="maximumSize">
<size>
<width>60</width>
<height>16777215</height>
</size>
</property>
<property name="suffix">
<string>%</string>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>100</number>
</property>
</widget>
</item>

View File

@ -42,7 +42,7 @@ class SearchThread(QtCore.QThread):
searchComplete = pyqtSignal()
progressUpdate = pyqtSignal(int, int)
def __init__(self, series_name: str, refresh: bool, literal: bool = False) -> None:
def __init__(self, series_name: str, refresh: bool, literal: bool = False, series_match_thresh: int = 90) -> None:
QtCore.QThread.__init__(self)
self.series_name = series_name
self.refresh: bool = refresh
@ -50,9 +50,10 @@ class SearchThread(QtCore.QThread):
self.cv_error = False
self.cv_search_results: list[CVVolumeResults] = []
self.literal = literal
self.series_match_thresh = series_match_thresh
def run(self) -> None:
comic_vine = ComicVineTalker()
comic_vine = ComicVineTalker(self.series_match_thresh)
try:
self.cv_error = False
self.cv_search_results = comic_vine.search_for_series(
@ -176,7 +177,6 @@ class VolumeSelectionWindow(QtWidgets.QDialog):
self.perform_query(refresh=False)
def auto_select(self) -> None:
if self.comic_archive is None:
QtWidgets.QMessageBox.information(self, "Auto-Select", "You need to load a comic first!")
return
@ -310,7 +310,9 @@ class VolumeSelectionWindow(QtWidgets.QDialog):
self.progdialog.canceled.connect(self.search_canceled)
self.progdialog.setModal(True)
self.progdialog.setMinimumDuration(300)
self.search_thread = SearchThread(self.series_name, refresh, self.literal)
self.search_thread = SearchThread(
self.series_name, refresh, self.literal, self.settings.id_series_match_search_thresh
)
self.search_thread.searchComplete.connect(self.search_complete)
self.search_thread.progressUpdate.connect(self.search_progress_update)
self.search_thread.start()

View File

@ -7,5 +7,6 @@ py7zr
pycountry
requests==2.*
text2digits
thefuzz[speedup]>=0.19.0
typing_extensions
wordninja