Merge branch 'mizaki-talker_settings' into develop
This commit is contained in:
commit
ee426e6473
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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",
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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)
|
||||
|
18
comictaggerlib/ctoptions/talker_plugins.py
Normal file
18
comictaggerlib/ctoptions/talker_plugins.py
Normal 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)
|
@ -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 = (
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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):
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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"]
|
||||
)
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user