Merge branch 'mizaki-talker_settings' into develop

This commit is contained in:
Timmy Welch 2023-02-03 18:14:26 -08:00
commit ee426e6473
No known key found for this signature in database
14 changed files with 172 additions and 138 deletions

View File

@ -49,7 +49,7 @@ class AutoTagStartWindow(QtWidgets.QDialog):
self.cbxIgnoreLeadingDigitsInFilename.setChecked(self.options.autotag_ignore_leading_numbers_in_filename)
self.cbxRemoveAfterSuccess.setChecked(self.options.autotag_remove_archive_after_successful_match)
self.cbxWaitForRateLimit.setChecked(self.options.autotag_wait_and_retry_on_rate_limit)
self.cbxAutoImprint.setChecked(self.options.comicvine_auto_imprint)
self.cbxAutoImprint.setChecked(self.options.talkers_auto_imprint)
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
@ -75,7 +75,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.options.comicvine_series_match_search_thresh
self.name_length_match_tolerance = self.options.talkers_series_match_search_thresh
self.split_words = self.cbxSplitWords.isChecked()
def search_string_toggle(self) -> None:

View File

@ -108,7 +108,7 @@ class CLI:
ca = match_set.ca
md = self.create_local_metadata(ca)
ct_md = self.actual_issue_data_fetch(match_set.matches[int(i) - 1]["issue_id"])
if self.options.comicvine_clear_metadata_on_import:
if self.options.talkers_clear_metadata_on_import:
md = ct_md
else:
notes = (
@ -117,7 +117,7 @@ class CLI:
)
md.overlay(ct_md.replace(notes=utils.combine_notes(md.notes, notes, "Tagged with ComicTagger")))
if self.options.comicvine_auto_imprint:
if self.options.talkers_auto_imprint:
md.fix_publisher()
self.actual_metadata_save(ca, md)
@ -421,7 +421,7 @@ class CLI:
match_results.fetch_data_failures.append(str(ca.path.absolute()))
return
if self.options.comicvine_clear_metadata_on_import:
if self.options.talkers_clear_metadata_on_import:
md = ct_md
else:
notes = (
@ -430,7 +430,7 @@ class CLI:
)
md.overlay(ct_md.replace(notes=utils.combine_notes(md.notes, notes, "Tagged with ComicTagger")))
if self.options.comicvine_auto_imprint:
if self.options.talkers_auto_imprint:
md.fix_publisher()
# ok, done building our metadata. time to save

View File

@ -3,6 +3,7 @@ from __future__ import annotations
from comictaggerlib.ctoptions.cmdline import initial_cmd_line_parser, register_commandline, validate_commandline_options
from comictaggerlib.ctoptions.file import register_settings, validate_settings
from comictaggerlib.ctoptions.plugin import register_plugin_settings, validate_plugin_settings
from comictaggerlib.ctoptions.talker_plugins import register_talker_settings
from comictaggerlib.ctoptions.types import ComicTaggerPaths
__all__ = [
@ -10,6 +11,7 @@ __all__ = [
"register_commandline",
"register_settings",
"register_plugin_settings",
"register_talker_settings",
"validate_commandline_options",
"validate_settings",
"validate_plugin_settings",

View File

@ -299,8 +299,8 @@ def validate_commandline_options(options: settngs.Config[settngs.Values], parser
if (
options[0].commands_only_set_cv_key
and options[0].comicvine_cv_api_key is None
and options[0].comicvine_cv_url is None
and options[0].talker_comicvine_cv_api_key is None
and options[0].talker_comicvine_cv_url is None
):
parser.exit(message="Key not given!\n", status=1)

View File

@ -85,14 +85,14 @@ def filename(parser: settngs.Manager) -> None:
)
def comicvine(parser: settngs.Manager) -> None:
# Comic Vine settings
def talkers(parser: settngs.Manager) -> None:
# General settings for all information talkers
parser.add_setting("--source", default="comicvine", help="Use a specified source by source ID")
parser.add_setting(
"--series-match-search-thresh",
default=90,
type=int,
)
parser.add_setting("--use-series-start-as-volume", default=False, action=argparse.BooleanOptionalAction)
parser.add_setting(
"--clear-metadata",
default=True,
@ -100,20 +100,6 @@ def comicvine(parser: settngs.Manager) -> None:
dest="clear_metadata_on_import",
action=argparse.BooleanOptionalAction,
)
parser.add_setting(
"--remove-html-tables",
default=False,
action=argparse.BooleanOptionalAction,
help="Removes html tables instead of converting them to text",
)
parser.add_setting(
"--cv-api-key",
help="Use the given Comic Vine API Key (persisted in settings).",
)
parser.add_setting(
"--cv-url",
help="Use the given Comic Vine URL (persisted in settings).",
)
parser.add_setting(
"-a",
"--auto-imprint",
@ -138,10 +124,10 @@ def comicvine(parser: settngs.Manager) -> None:
help="Enables the publisher filter",
)
parser.add_setting(
"--clear-form-before-populating-from-cv",
"--clear-form-before-populating",
default=False,
action=argparse.BooleanOptionalAction,
help="Clears all existing metadata when applying metadata from ComicVine",
help="Clears all existing metadata when applying metadata from comic source",
)
@ -255,7 +241,7 @@ def register_settings(parser: settngs.Manager) -> None:
parser.add_group("identifier", identifier, False)
parser.add_group("dialog", dialog, False)
parser.add_group("filename", filename, False)
parser.add_group("comicvine", comicvine, False)
parser.add_group("talkers", talkers, False)
parser.add_group("cbl", cbl, False)
parser.add_group("rename", rename, False)
parser.add_group("autotag", autotag, False)

View File

@ -0,0 +1,18 @@
from __future__ import annotations
import logging
from collections.abc import Mapping
import settngs
from comictalker.talkerbase import ComicTalker
logger = logging.getLogger(__name__)
def register_talker_settings(parser: settngs.Manager, plugins: Mapping[str, ComicTalker]) -> None:
for talker_name, talker in plugins.items():
try:
parser.add_group("talker_" + talker_name, talker.register_settings, False)
except Exception:
logger.exception("Failed to register settings for %s", talker_name)

View File

@ -20,6 +20,7 @@ import json
import logging.handlers
import signal
import sys
from collections.abc import Mapping
import settngs
@ -28,7 +29,7 @@ import comictalker.comictalkerapi as ct_api
from comictaggerlib import cli, ctoptions
from comictaggerlib.ctversion import version
from comictaggerlib.log import setup_logging
from comictalker.talkerbase import TalkerError
from comictalker.talkerbase import ComicTalker
if sys.version_info < (3, 10):
import importlib_metadata
@ -65,13 +66,15 @@ class App:
self.options = settngs.Config({}, {})
self.initial_arg_parser = ctoptions.initial_cmd_line_parser()
self.config_load_success = False
self.talker_plugins: Mapping[str, ComicTalker] = {}
def run(self) -> None:
opts = self.initialize()
self.load_plugins()
self.initialize_dirs(opts.config)
self.talker_plugins = ct_api.get_talkers(version, opts.config.user_cache_dir)
self.register_options()
self.parse_options(opts.config)
self.initialize_dirs()
self.main()
@ -92,11 +95,13 @@ class App:
ctoptions.register_commandline(self.manager)
ctoptions.register_settings(self.manager)
ctoptions.register_plugin_settings(self.manager)
ctoptions.register_talker_settings(self.manager, self.talker_plugins)
def parse_options(self, config_paths: ctoptions.ComicTaggerPaths) -> None:
self.options, self.config_load_success = self.manager.parse_config(
config_paths.user_config_dir / "settings.json"
)
self.initialize_talkers()
self.options = self.manager.get_namespace(self.options)
self.options = ctoptions.validate_commandline_options(self.options, self.manager)
@ -104,17 +109,27 @@ class App:
self.options = ctoptions.validate_plugin_settings(self.options)
self.options = self.options
def initialize_dirs(self) -> None:
self.options[0].runtime_config.user_data_dir.mkdir(parents=True, exist_ok=True)
self.options[0].runtime_config.user_config_dir.mkdir(parents=True, exist_ok=True)
self.options[0].runtime_config.user_cache_dir.mkdir(parents=True, exist_ok=True)
self.options[0].runtime_config.user_state_dir.mkdir(parents=True, exist_ok=True)
self.options[0].runtime_config.user_log_dir.mkdir(parents=True, exist_ok=True)
logger.debug("user_data_dir: %s", self.options[0].runtime_config.user_data_dir)
logger.debug("user_config_dir: %s", self.options[0].runtime_config.user_config_dir)
logger.debug("user_cache_dir: %s", self.options[0].runtime_config.user_cache_dir)
logger.debug("user_state_dir: %s", self.options[0].runtime_config.user_state_dir)
logger.debug("user_log_dir: %s", self.options[0].runtime_config.user_log_dir)
def initialize_dirs(self, paths: ctoptions.ComicTaggerPaths) -> None:
paths.user_data_dir.mkdir(parents=True, exist_ok=True)
paths.user_config_dir.mkdir(parents=True, exist_ok=True)
paths.user_cache_dir.mkdir(parents=True, exist_ok=True)
paths.user_state_dir.mkdir(parents=True, exist_ok=True)
paths.user_log_dir.mkdir(parents=True, exist_ok=True)
logger.debug("user_data_dir: %s", paths.user_data_dir)
logger.debug("user_config_dir: %s", paths.user_config_dir)
logger.debug("user_cache_dir: %s", paths.user_cache_dir)
logger.debug("user_state_dir: %s", paths.user_state_dir)
logger.debug("user_log_dir: %s", paths.user_log_dir)
def initialize_talkers(self) -> None:
# Apply talker settings from config file
for talker_name, talker in list(self.talker_plugins.items()):
try:
talker.parse_settings(self.options[0]["talker_" + talker_name])
except Exception as e:
# Remove talker as we failed to apply the settings
del self.talker_plugins[talker_name] # type: ignore[attr-defined]
logger.exception("Failed to initialize talker settings. Error %s", e)
def main(self) -> None:
assert self.options is not None
@ -134,32 +149,17 @@ class App:
self.options[0].runtime_no_gui = True
logger.warning("PyQt5 is not available. ComicTagger is limited to command-line mode.")
# manage the CV API key
# None comparison is used so that the empty string can unset the value
if self.options[0].comicvine_cv_api_key is not None or self.options[0].comicvine_cv_url is not None:
settings_path = self.options[0].runtime_config.user_config_dir / "settings.json"
if self.config_load_success:
self.manager.save_file(self.options[0], settings_path)
if self.options[0].commands_only_set_cv_key:
if self.config_load_success:
print("Key set") # noqa: T201
return
try:
talker_api = ct_api.get_comic_talker("comicvine")( # type: ignore[call-arg]
version=version,
cache_folder=self.options[0].runtime_config.user_cache_dir,
series_match_thresh=self.options[0].comicvine_series_match_search_thresh,
remove_html_tables=self.options[0].comicvine_remove_html_tables,
use_series_start_as_volume=self.options[0].comicvine_use_series_start_as_volume,
wait_on_ratelimit=self.options[0].autotag_wait_and_retry_on_rate_limit,
api_url=self.options[0].comicvine_cv_url,
api_key=self.options[0].comicvine_cv_api_key,
)
except TalkerError as e:
logger.exception("Unable to load talker")
error = (str(e), True)
talker_api = self.talker_plugins[self.options[0].talkers_source]
except Exception:
logger.exception(f"Unable to load talker {self.options[0].talkers_source}")
# TODO error True can be changed to False after the talker settings menu generation is in
error = (f"Unable to load talker {self.options[0].talkers_source}", True)
if not self.config_load_success:
error = (

View File

@ -65,7 +65,7 @@ class SearchThread(QtCore.QThread):
try:
self.ct_error = False
self.ct_search_results = self.talker_api.search_for_series(
self.series_name, self.prog_callback, self.refresh, self.literal
self.series_name, self.prog_callback, self.refresh, self.literal, self.series_match_thresh
)
except TalkerError as e:
self.ct_search_results = []
@ -156,7 +156,7 @@ class SeriesSelectionWindow(QtWidgets.QDialog):
self.progdialog: QtWidgets.QProgressDialog | None = None
self.search_thread: SearchThread | None = None
self.use_filter = self.options.comicvine_always_use_publisher_filter
self.use_filter = self.options.talkers_always_use_publisher_filter
# Load to retrieve settings
self.talker_api = talker_api
@ -343,7 +343,7 @@ class SeriesSelectionWindow(QtWidgets.QDialog):
def perform_query(self, refresh: bool = False) -> None:
self.search_thread = SearchThread(
self.talker_api, self.series_name, refresh, self.literal, self.options.comicvine_series_match_search_thresh
self.talker_api, self.series_name, refresh, self.literal, self.options.talkers_series_match_search_thresh
)
self.search_thread.searchComplete.connect(self.search_complete)
self.search_thread.progressUpdate.connect(self.search_progress_update)
@ -410,7 +410,7 @@ class SeriesSelectionWindow(QtWidgets.QDialog):
# compare as str in case extra chars ie. '1976?'
# - missing (none) values being converted to 'None' - consistent with prior behaviour in v1.2.3
# sort by start_year if set
if self.options.comicvine_sort_series_by_year:
if self.options.talkers_sort_series_by_year:
try:
self.ct_search_results = sorted(
self.ct_search_results,
@ -428,7 +428,7 @@ class SeriesSelectionWindow(QtWidgets.QDialog):
logger.exception("bad data error sorting results by count_of_issues")
# move sanitized matches to the front
if self.options.comicvine_exact_series_matches_first:
if self.options.talkers_exact_series_matches_first:
try:
sanitized = utils.sanitize_title(self.series_name, False).casefold()
sanitized_no_articles = utils.sanitize_title(self.series_name, True).casefold()

View File

@ -274,7 +274,7 @@ class SettingsWindow(QtWidgets.QDialog):
else:
self.leRarExePath.setEnabled(False)
self.sbNameMatchIdentifyThresh.setValue(self.options[0].identifier_series_match_identify_thresh)
self.sbNameMatchSearchThresh.setValue(self.options[0].comicvine_series_match_search_thresh)
self.sbNameMatchSearchThresh.setValue(self.options[0].talkers_series_match_search_thresh)
self.tePublisherFilter.setPlainText("\n".join(self.options[0].identifier_publisher_filter))
self.cbxCheckForNewVersion.setChecked(self.options[0].general_check_for_new_version)
@ -285,16 +285,16 @@ class SettingsWindow(QtWidgets.QDialog):
self.cbxRemovePublisher.setChecked(self.options[0].filename_remove_publisher)
self.switch_parser()
self.cbxUseSeriesStartAsVolume.setChecked(self.options[0].comicvine_use_series_start_as_volume)
self.cbxClearFormBeforePopulating.setChecked(self.options[0].comicvine_clear_form_before_populating_from_cv)
self.cbxRemoveHtmlTables.setChecked(self.options[0].comicvine_remove_html_tables)
self.cbxUseSeriesStartAsVolume.setChecked(self.options[0].talker_comicvine_cv_use_series_start_as_volume)
self.cbxClearFormBeforePopulating.setChecked(self.options[0].talkers_clear_form_before_populating)
self.cbxRemoveHtmlTables.setChecked(self.options[0].talker_comicvine_cv_remove_html_tables)
self.cbxUseFilter.setChecked(self.options[0].comicvine_always_use_publisher_filter)
self.cbxSortByYear.setChecked(self.options[0].comicvine_sort_series_by_year)
self.cbxExactMatches.setChecked(self.options[0].comicvine_exact_series_matches_first)
self.cbxUseFilter.setChecked(self.options[0].talkers_always_use_publisher_filter)
self.cbxSortByYear.setChecked(self.options[0].talkers_sort_series_by_year)
self.cbxExactMatches.setChecked(self.options[0].talkers_exact_series_matches_first)
self.leKey.setText(self.options[0].comicvine_cv_api_key)
self.leURL.setText(self.options[0].comicvine_cv_url)
self.leKey.setText(self.options[0].talker_comicvine_cv_api_key)
self.leURL.setText(self.options[0].talker_comicvine_cv_url)
self.cbxAssumeLoneCreditIsPrimary.setChecked(self.options[0].cbl_assume_lone_credit_is_primary)
self.cbxCopyCharactersToTags.setChecked(self.options[0].cbl_copy_characters_to_tags)
@ -390,7 +390,7 @@ class SettingsWindow(QtWidgets.QDialog):
self.options[0].general_check_for_new_version = self.cbxCheckForNewVersion.isChecked()
self.options[0].identifier_series_match_identify_thresh = self.sbNameMatchIdentifyThresh.value()
self.options[0].comicvine_series_match_search_thresh = self.sbNameMatchSearchThresh.value()
self.options[0].talkers_series_match_search_thresh = self.sbNameMatchSearchThresh.value()
self.options[0].identifier_publisher_filter = [
x.strip() for x in str(self.tePublisherFilter.toPlainText()).splitlines() if x.strip()
]
@ -400,21 +400,21 @@ class SettingsWindow(QtWidgets.QDialog):
self.options[0].filename_remove_fcbd = self.cbxRemoveFCBD.isChecked()
self.options[0].filename_remove_publisher = self.cbxRemovePublisher.isChecked()
self.options[0].comicvine_use_series_start_as_volume = self.cbxUseSeriesStartAsVolume.isChecked()
self.options[0].comicvine_clear_form_before_populating_from_cv = self.cbxClearFormBeforePopulating.isChecked()
self.options[0].comicvine_remove_html_tables = self.cbxRemoveHtmlTables.isChecked()
self.options[0].talker_comicvine_cv_use_series_start_as_volume = self.cbxUseSeriesStartAsVolume.isChecked()
self.options[0].talkers_clear_form_before_populating = self.cbxClearFormBeforePopulating.isChecked()
self.options[0].talker_comicvine_cv_remove_html_tables = self.cbxRemoveHtmlTables.isChecked()
self.options[0].comicvine_always_use_publisher_filter = self.cbxUseFilter.isChecked()
self.options[0].comicvine_sort_series_by_year = self.cbxSortByYear.isChecked()
self.options[0].comicvine_exact_series_matches_first = self.cbxExactMatches.isChecked()
self.options[0].talkers_always_use_publisher_filter = self.cbxUseFilter.isChecked()
self.options[0].talkers_sort_series_by_year = self.cbxSortByYear.isChecked()
self.options[0].talkers_exact_series_matches_first = self.cbxExactMatches.isChecked()
if self.leKey.text().strip():
self.options[0].comicvine_cv_api_key = self.leKey.text().strip()
self.talker_api.api_key = self.options[0].comicvine_cv_api_key
self.options[0].talker_comicvine_cv_api_key = self.leKey.text().strip()
self.talker_api.api_key = self.options[0].talker_comicvine_cv_api_key
if self.leURL.text().strip():
self.options[0].comicvine_cv_url = self.leURL.text().strip()
self.talker_api.api_url = self.options[0].comicvine_cv_url
self.options[0].talker_comicvine_cv_url = self.leURL.text().strip()
self.talker_api.api_url = self.options[0].talker_comicvine_cv_url
self.options[0].cbl_assume_lone_credit_is_primary = self.cbxAssumeLoneCreditIsPrimary.isChecked()
self.options[0].cbl_copy_characters_to_tags = self.cbxCopyCharactersToTags.isChecked()

View File

@ -1075,7 +1075,7 @@ Have fun!
if self.options[0].cbl_apply_transform_on_import:
new_metadata = CBLTransformer(new_metadata, self.options[0]).apply()
if self.options[0].comicvine_clear_form_before_populating_from_cv:
if self.options[0].talkers_clear_form_before_populating:
self.clear_form()
notes = (
@ -1793,7 +1793,7 @@ Have fun!
)
md.overlay(ct_md.replace(notes=utils.combine_notes(md.notes, notes, "Tagged with ComicTagger")))
if self.options[0].comicvine_auto_imprint:
if self.options[0].talkers_auto_imprint:
md.fix_publisher()
if not ca.write_metadata(md, self.save_data_style):

View File

@ -16,6 +16,8 @@
from __future__ import annotations
import logging
import pathlib
from collections.abc import Mapping
import comictalker.talkers.comicvine
from comictalker.talkerbase import ComicTalker, TalkerError
@ -23,16 +25,16 @@ from comictalker.talkerbase import ComicTalker, TalkerError
logger = logging.getLogger(__name__)
def get_comic_talker(source_name: str) -> type[ComicTalker]:
"""Retrieve the available sources modules"""
sources = get_talkers()
if source_name not in sources:
raise TalkerError(source=source_name, code=4, desc="The talker does not exist")
def get_talkers(version: str, cache: pathlib.Path) -> Mapping[str, ComicTalker]:
"""Returns all comic talker instances"""
# TODO separate PR will bring talkers in via entry points. TalkerError etc. source will then be a var
talkers: dict[str, ComicTalker] = {}
talker = sources[source_name]
return talker
def get_talkers() -> dict[str, type[ComicTalker]]:
"""Returns all comic talker modules NOT objects"""
return {"comicvine": comictalker.talkers.comicvine.ComicVineTalker}
for talker in [comictalker.talkers.comicvine.ComicVineTalker]:
try:
obj = talker(version, cache)
talkers[obj.source_details.id] = obj
except Exception:
logger.exception("Failed to load talker: %s", "comicvine")
raise TalkerError(source="comicvine", code=4, desc="Failed to initialise talker")
return talkers

View File

@ -15,8 +15,9 @@ from __future__ import annotations
import logging
import pathlib
from typing import Callable
from urllib.parse import urlsplit
from typing import Any, Callable
import settngs
from comicapi.genericmetadata import GenericMetadata
from comictalker.resulttypes import ComicIssue, ComicSeries
@ -139,27 +140,23 @@ class TalkerDataError(TalkerError):
class ComicTalker:
"""The base class for all comic source talkers"""
default_api_url: str = ""
default_api_key: str = ""
def __init__(self, version: str, cache_folder: pathlib.Path, api_url: str = "", api_key: str = "") -> None:
def __init__(self, version: str, cache_folder: pathlib.Path) -> None:
# Identity name for the information source etc.
self.source_details = SourceDetails()
self.static_options = SourceStaticOptions()
self.api_key = api_key
self.cache_folder = cache_folder
self.version = version
self.api_key: str = ""
self.api_url: str = ""
self.api_key = api_key or self.default_api_key
self.api_url = api_url or self.default_api_url
def register_settings(self, parser: settngs.Manager) -> None:
"""Allows registering settings using the settngs package with an argparse like interface"""
return None
tmp_url = urlsplit(self.api_url)
# joinurl only works properly if there is a trailing slash
if tmp_url.path and tmp_url.path[-1] != "/":
tmp_url = tmp_url._replace(path=tmp_url.path + "/")
self.api_url = tmp_url.geturl()
def parse_settings(self, settings: dict[str, Any]) -> None:
"""settings is a dictionary of options defined in register_settings.
It is only guaranteed that the settings defined in register_settings will be present."""
return None
def check_api_key(self, key: str, url: str) -> bool:
"""
@ -174,6 +171,7 @@ class ComicTalker:
callback: Callable[[int, int], None] | None = None,
refresh_cache: bool = False,
literal: bool = False,
series_match_thresh: int = 90,
) -> list[ComicSeries]:
"""
This function should return a list of series that match the given series name

View File

@ -16,6 +16,7 @@ ComicVine information source
# limitations under the License.
from __future__ import annotations
import argparse
import json
import logging
import pathlib
@ -24,6 +25,7 @@ from typing import Any, Callable, Generic, TypeVar
from urllib.parse import urljoin, urlsplit
import requests
import settngs
from typing_extensions import Required, TypedDict
import comictalker.talker_utils as talker_utils
@ -152,21 +154,12 @@ CV_RATE_LIMIT_STATUS = 107
class ComicVineTalker(ComicTalker):
default_api_key = "27431e6787042105bd3e47e169a624521f89f3a4"
default_api_url = "https://comicvine.gamespot.com/api"
def __init__(
self,
version: str,
cache_folder: pathlib.Path,
api_url: str = "",
api_key: str = "",
series_match_thresh: int = 90,
remove_html_tables: bool = False,
use_series_start_as_volume: bool = False,
wait_on_ratelimit: bool = False,
):
super().__init__(version, cache_folder, api_url, api_key)
super().__init__(version, cache_folder)
self.source_details = SourceDetails(
name="Comic Vine",
ident="comicvine",
@ -181,19 +174,58 @@ class ComicVineTalker(ComicTalker):
has_nsfw=False,
has_censored_covers=False,
)
# Default settings
self.api_url: str = "https://comicvine.gamespot.com/api"
self.api_key: str = "27431e6787042105bd3e47e169a624521f89f3a4"
self.remove_html_tables: bool = False
self.use_series_start_as_volume: bool = False
self.wait_for_rate_limit: bool = False
# Identity name for the information source
self.source_name: str = self.source_details.id
self.source_name_friendly: str = self.source_details.name
self.wait_for_rate_limit: bool = wait_on_ratelimit
# NOTE: This was hardcoded before which is why it isn't passed in
tmp_url = urlsplit(self.api_url)
# joinurl only works properly if there is a trailing slash
if tmp_url.path and tmp_url.path[-1] != "/":
tmp_url = tmp_url._replace(path=tmp_url.path + "/")
self.api_url = tmp_url.geturl()
# NOTE: This was hardcoded before which is why it isn't in settings
self.wait_for_rate_limit_time: int = 20
self.remove_html_tables: bool = remove_html_tables
self.use_series_start_as_volume: bool = use_series_start_as_volume
def register_settings(self, parser: settngs.Manager) -> None:
parser.add_setting("--cv-use-series-start-as-volume", default=False, action=argparse.BooleanOptionalAction)
parser.add_setting("--cv-wait-on-ratelimit", default=False, action=argparse.BooleanOptionalAction)
parser.add_setting(
"--cv-remove-html-tables",
default=False,
action=argparse.BooleanOptionalAction,
help="Removes html tables instead of converting them to text.",
)
parser.add_setting(
"--cv-api-key",
help="Use the given Comic Vine API Key.",
)
parser.add_setting(
"--cv-url",
help="Use the given Comic Vine URL.",
)
self.series_match_thresh: int = series_match_thresh
def parse_settings(self, settings: dict[str, Any]) -> None:
self.remove_html_tables = settings["cv_remove_html_tables"]
self.use_series_start_as_volume = settings["cv_use_series_start_as_volume"]
if settings["cv_api_key"]:
self.api_key = settings["cv_api_key"]
if settings["cv_url"]:
tmp_url = urlsplit(settings["cv_url"])
# joinurl only works properly if there is a trailing slash
if tmp_url.path and tmp_url.path[-1] != "/":
tmp_url = tmp_url._replace(path=tmp_url.path + "/")
self.api_url = tmp_url.geturl()
def check_api_key(self, key: str, url: str) -> bool:
if not url:
@ -379,6 +411,7 @@ class ComicVineTalker(ComicTalker):
callback: Callable[[int, int], None] | None = None,
refresh_cache: bool = False,
literal: bool = False,
series_match_thresh: int = 90,
) -> list[ComicSeries]:
# Sanitize the series name for comicvine searching, comicvine search ignore symbols
search_series_name = utils.sanitize_title(series_name, literal)
@ -437,7 +470,7 @@ class ComicVineTalker(ComicTalker):
if not literal:
# Stop searching once any entry falls below the threshold
stop_searching = any(
not utils.titles_match(search_series_name, series["name"], self.series_match_thresh)
not utils.titles_match(search_series_name, series["name"], series_match_thresh)
for series in cv_response["results"]
)

View File

@ -16,6 +16,7 @@ import comicapi.comicarchive
import comicapi.genericmetadata
import comictaggerlib.ctoptions
import comictalker.comiccacher
import comictalker.comictalkerapi
import comictalker.talkers.comicvine
from comicapi import utils
from testing import comicvine, filenames
@ -118,12 +119,6 @@ def comicvine_api(
cv = comictalker.talkers.comicvine.ComicVineTalker(
version=mock_version[0],
cache_folder=options[0].runtime_config.user_cache_dir,
api_url="",
api_key="",
series_match_thresh=90,
remove_html_tables=False,
use_series_start_as_volume=False,
wait_on_ratelimit=False,
)
return cv