Use new settings system for plugin

This commit is contained in:
Mizaki 2023-01-02 01:04:15 +00:00
parent 0ac5b59a1e
commit 2d8c47edca
10 changed files with 126 additions and 91 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_general_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

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_general_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_general_auto_imprint:
md.fix_publisher()
self.actual_metadata_save(ca, md)
@ -428,7 +428,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_general_clear_metadata_on_import:
md = ct_md
else:
notes = (
@ -437,7 +437,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_general_auto_imprint:
md.fix_publisher()
# ok, done building our metadata. time to save

View File

@ -93,13 +93,9 @@ def filename(parser: settngs.Manager) -> None:
)
def comicvine(parser: settngs.Manager) -> None:
# Comic Vine settings
parser.add_setting(
"--series-match-search-thresh",
default=90,
type=int,
)
def talkers_general(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("--use-series-start-as-volume", default=False, action=argparse.BooleanOptionalAction)
parser.add_setting(
"--clear-metadata",
@ -108,20 +104,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",
@ -146,10 +128,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",
)
@ -257,13 +239,17 @@ def validate_settings(options: settngs.Config[settngs.Values], parser: settngs.M
return options
def register_settings(parser: settngs.Manager) -> None:
def register_settings(parser: settngs.Manager, talkers: dict[str, Any]) -> None:
parser.add_group("general", general, False)
parser.add_group("internal", internal, False)
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_general", talkers_general, False)
parser.add_group("cbl", cbl, False)
parser.add_group("rename", rename, False)
parser.add_group("autotag", autotag, False)
# Register talker plugin settings
for talker, cls in talkers.items():
parser.add_group(talker, cls.comic_settings, False)

View File

@ -66,8 +66,10 @@ class App:
self.options = settngs.Config({}, {})
self.initial_arg_parser = ctoptions.initial_cmd_line_parser()
self.config_load_success = False
self.talker_plugins: dict = {}
def run(self) -> None:
self.talker_plugins = ct_api.get_talkers()
opts = self.initialize()
self.register_options()
self.parse_options(opts.config)
@ -87,7 +89,7 @@ class App:
"For more help visit the wiki at: https://github.com/comictagger/comictagger/wiki",
)
ctoptions.register_commandline(self.manager)
ctoptions.register_settings(self.manager)
ctoptions.register_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(
@ -99,6 +101,18 @@ class App:
self.options = ctoptions.validate_settings(self.options, self.manager)
self.options = self.options
# parse talker settings
for loaded in self.talker_plugins.values():
parse_options = getattr(loaded, "parse_settings", None)
if parse_options is None:
logger.warning(f"Failed to find parse_settings in talker {loaded}")
continue
try:
parse_options(self.options)
except Exception as e:
logger.warning(f"Failed to parse talker options for {loaded}: {e}")
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)
@ -136,28 +150,12 @@ 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
# TODO Have option to save passed in config options and quit?
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")

View File

@ -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_general_always_use_publisher_filter
# Load to retrieve settings
self.talker_api = talker_api
@ -395,7 +395,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_general_sort_series_by_year:
try:
self.ct_search_results = sorted(
self.ct_search_results,
@ -413,7 +413,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_general_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

@ -282,13 +282,13 @@ 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].comicvine_cv_use_series_start_as_volume)
self.cbxClearFormBeforePopulating.setChecked(self.options[0].talkers_general_clear_form_before_populating)
self.cbxRemoveHtmlTables.setChecked(self.options[0].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_general_always_use_publisher_filter)
self.cbxSortByYear.setChecked(self.options[0].talkers_general_sort_series_by_year)
self.cbxExactMatches.setChecked(self.options[0].talkers_general_exact_series_matches_first)
self.leKey.setText(self.options[0].comicvine_cv_api_key)
self.leURL.setText(self.options[0].comicvine_cv_url)
@ -396,13 +396,13 @@ 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].comicvine_cv_use_series_start_as_volume = self.cbxUseSeriesStartAsVolume.isChecked()
self.options[0].talkers_general_clear_form_before_populating = self.cbxClearFormBeforePopulating.isChecked()
self.options[0].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_general_always_use_publisher_filter = self.cbxUseFilter.isChecked()
self.options[0].talkers_general_sort_series_by_year = self.cbxSortByYear.isChecked()
self.options[0].talkers_general_exact_series_matches_first = self.cbxExactMatches.isChecked()
if self.leKey.text().strip():
self.options[0].comicvine_cv_api_key = self.leKey.text().strip()

View File

@ -1084,7 +1084,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_general_clear_form_before_populating:
self.clear_form()
notes = (
@ -1802,7 +1802,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_general_auto_imprint:
md.fix_publisher()
if not ca.write_metadata(md, self.save_data_style):

View File

@ -13,10 +13,12 @@
# limitations under the License.
from __future__ import annotations
import argparse
import logging
import pathlib
from typing import Callable
from urllib.parse import urlsplit
import settngs
from comicapi.genericmetadata import GenericMetadata
from comictalker.resulttypes import ComicIssue, ComicSeries
@ -148,16 +150,16 @@ class ComicTalker:
self.cache_folder = cache_folder
self.version = version
self.api_key = api_key or self.default_api_key
self.api_url = api_url or self.default_api_url
self.api_key = ""
self.api_url = ""
tmp_url = urlsplit(self.api_url)
@classmethod
def comic_settings(cls, parser: settngs.Manager) -> None:
"""Talker settings."""
# 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()
@classmethod
def parse_settings(cls, settings: argparse.Namespace) -> None:
"""Parse settings."""
def check_api_key(self, key: str, url: str) -> bool:
"""

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
@ -155,18 +157,20 @@ class ComicVineTalker(ComicTalker):
default_api_key = "27431e6787042105bd3e47e169a624521f89f3a4"
default_api_url = "https://comicvine.gamespot.com/api"
# Settings
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
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")
self.static_options = SourceStaticOptions(
website="https://comicvine.gamespot.com/",
@ -181,14 +185,65 @@ class ComicVineTalker(ComicTalker):
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
# If cls api_url or api_key is empty, use default
self.api_url = ComicVineTalker.api_url or ComicVineTalker.default_api_url
self.api_key = ComicVineTalker.api_key or ComicVineTalker.default_api_key
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()
self.wait_for_rate_limit: bool = ComicVineTalker.wait_on_ratelimit
# NOTE: This was hardcoded before which is why it isn't passed in
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
self.remove_html_tables: bool = ComicVineTalker.remove_html_tables
self.use_series_start_as_volume: bool = ComicVineTalker.use_series_start_as_volume
self.series_match_thresh: int = series_match_thresh
self.series_match_thresh: int = ComicVineTalker.series_match_thresh
@classmethod
def comic_settings(cls, parser: settngs.Manager) -> None:
# Might be general settings?
parser.add_setting(
"--series-match-search-thresh",
default=90,
type=int,
)
parser.add_setting("--cv-use-series-start-as-volume", default=False, action=argparse.BooleanOptionalAction)
# Comic Vine settings
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.",
)
@classmethod
def parse_settings(cls, settings: settngs.Config) -> None:
"""Parse settings."""
if settings[0].comicvine_cv_remove_html_tables:
cls.remove_html_tables = bool(settings[0].comicvine_cv_remove_html_tables)
if settings[0].comicvine_cv_use_series_start_as_volume:
cls.use_series_start_as_volume = settings[0].comicvine_cv_use_series_start_as_volume
if settings[0].comicvine_cv_api_key:
cls.api_key = settings[0].comicvine_cv_api_key
if settings[0].comicvine_cv_url:
cls.api_url = settings[0].comicvine_cv_url
def check_api_key(self, key: str, url: str) -> bool:
if not url:

View File

@ -118,12 +118,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