From d9c02b0115fbe7c282c13a9318be019bc919fd4b Mon Sep 17 00:00:00 2001
From: Timmy Welch <timmy@narnian.us>
Date: Fri, 10 Jun 2022 15:23:58 -0700
Subject: [PATCH] Allow changing the ComicVine URL fixes #104

---
 comictaggerlib/comicvinetalker.py   | 17 +++---
 comictaggerlib/main.py              | 10 ++--
 comictaggerlib/options.py           |  8 ++-
 comictaggerlib/settings.py          |  5 ++
 comictaggerlib/settingswindow.py    | 11 ++--
 comictaggerlib/ui/settingswindow.ui | 88 ++++++++++++++++-------------
 6 files changed, 81 insertions(+), 58 deletions(-)

diff --git a/comictaggerlib/comicvinetalker.py b/comictaggerlib/comicvinetalker.py
index 7995e32..870f4b0 100644
--- a/comictaggerlib/comicvinetalker.py
+++ b/comictaggerlib/comicvinetalker.py
@@ -79,6 +79,7 @@ def url_fetch_complete(image_url: str, thumb_url: str | None) -> None:
 class ComicVineTalker:
     logo_url = "http://static.comicvine.com/bundles/comicvinesite/images/logo.png"
     api_key = ""
+    api_base_url = ""
 
     alt_url_list_fetch_complete = list_fetch_complete
     url_fetch_complete = url_fetch_complete
@@ -91,19 +92,16 @@ class ComicVineTalker:
         return "Comic Vine rate limit exceeded.  Please wait a bit."
 
     def __init__(self) -> None:
-
-        self.api_base_url = "https://comicvine.gamespot.com/api"
         self.wait_for_rate_limit = False
 
         # key that is registered to comictagger
         default_api_key = "27431e6787042105bd3e47e169a624521f89f3a4"
+        default_url = "https://comicvine.gamespot.com/api"
 
         self.issue_id: int | None = None
 
-        if ComicVineTalker.api_key == "":
-            self.api_key = default_api_key
-        else:
-            self.api_key = ComicVineTalker.api_key
+        self.api_key = ComicVineTalker.api_key or default_api_key
+        self.api_base_url = ComicVineTalker.api_base_url or default_url
 
         self.log_func: Callable[[str], None] | None = None
 
@@ -132,10 +130,11 @@ class ComicVineTalker:
                     day = utils.xlate(parts[2], True)
         return day, month, year
 
-    def test_key(self, key: str) -> bool:
-
+    def test_key(self, key: str, url: str) -> bool:
+        if not url:
+            url = self.api_base_url
         try:
-            test_url = self.api_base_url + "/issue/1/?api_key=" + key + "&format=json&field_list=name"
+            test_url = url + "/issue/1/?api_key=" + key + "&format=json&field_list=name"
 
             cv_response: CVResult = requests.get(
                 test_url, headers={"user-agent": "comictagger/" + ctversion.version}
diff --git a/comictaggerlib/main.py b/comictaggerlib/main.py
index 52a3c87..35d8f5a 100755
--- a/comictaggerlib/main.py
+++ b/comictaggerlib/main.py
@@ -133,15 +133,17 @@ def ctmain() -> None:
     # Need to load setting before anything else
 
     # manage the CV API key
-    if opts.cv_api_key:
-        if opts.cv_api_key != SETTINGS.cv_api_key:
-            SETTINGS.cv_api_key = opts.cv_api_key
-            SETTINGS.save()
+    # None comparison is used so that the empty string can unset the value
+    if opts.cv_api_key is not None or opts.cv_url is not None:
+        SETTINGS.cv_api_key = opts.cv_api_key if opts.cv_api_key is not None else SETTINGS.cv_api_key
+        SETTINGS.cv_url = opts.cv_url if opts.cv_url is not None else SETTINGS.cv_url
+        SETTINGS.save()
     if opts.only_set_cv_key:
         print("Key set")  # noqa: T201
         return
 
     ComicVineTalker.api_key = SETTINGS.cv_api_key
+    ComicVineTalker.api_base_url = SETTINGS.cv_url
 
     signal.signal(signal.SIGINT, signal.SIG_DFL)
 
diff --git a/comictaggerlib/options.py b/comictaggerlib/options.py
index a078030..ca58e98 100644
--- a/comictaggerlib/options.py
+++ b/comictaggerlib/options.py
@@ -111,6 +111,10 @@ def define_args() -> argparse.ArgumentParser:
         "--cv-api-key",
         help="Use the given Comic Vine API Key (persisted in settings).",
     )
+    parser.add_argument(
+        "--cv-url",
+        help="Use the given Comic Vine URL (persisted in settings).",
+    )
     parser.add_argument(
         "--delete-rar",
         action="store_true",
@@ -376,8 +380,8 @@ def parse_cmd_line() -> argparse.Namespace:
         for item in globs:
             opts.files.extend(glob.glob(item))
 
-    if opts.only_set_cv_key and opts.cv_api_key is None:
-        parser.exit(message="Key not given!", status=1)
+    if opts.only_set_cv_key and opts.cv_api_key is None and opts.cv_url is None:
+        parser.exit(message="Key not given!\n", status=1)
 
     if not opts.only_set_cv_key and opts.no_gui and not opts.files:
         parser.exit(message="Command requires at least one filename!\n", status=1)
diff --git a/comictaggerlib/settings.py b/comictaggerlib/settings.py
index 501cc0c..26a75d1 100644
--- a/comictaggerlib/settings.py
+++ b/comictaggerlib/settings.py
@@ -98,6 +98,7 @@ class ComicTaggerSettings:
         self.clear_form_before_populating_from_cv = False
         self.remove_html_tables = False
         self.cv_api_key = ""
+        self.cv_url = ""
         self.auto_imprint = False
 
         self.sort_series_by_year = True
@@ -256,6 +257,9 @@ class ComicTaggerSettings:
         if self.config.has_option("comicvine", "cv_api_key"):
             self.cv_api_key = self.config.get("comicvine", "cv_api_key")
 
+        if self.config.has_option("comicvine", "cv_url"):
+            self.cv_url = self.config.get("comicvine", "cv_url")
+
         if self.config.has_option("cbl_transform", "assume_lone_credit_is_primary"):
             self.assume_lone_credit_is_primary = self.config.getboolean(
                 "cbl_transform", "assume_lone_credit_is_primary"
@@ -377,6 +381,7 @@ class ComicTaggerSettings:
         self.config.set("comicvine", "always_use_publisher_filter", self.always_use_publisher_filter)
 
         self.config.set("comicvine", "cv_api_key", self.cv_api_key)
+        self.config.set("comicvine", "cv_url", self.cv_url)
 
         if not self.config.has_section("cbl_transform"):
             self.config.add_section("cbl_transform")
diff --git a/comictaggerlib/settingswindow.py b/comictaggerlib/settingswindow.py
index cb9eb62..1ffafd2 100644
--- a/comictaggerlib/settingswindow.py
+++ b/comictaggerlib/settingswindow.py
@@ -237,7 +237,8 @@ class SettingsWindow(QtWidgets.QDialog):
         self.cbxSortByYear.setChecked(self.settings.sort_series_by_year)
         self.cbxExactMatches.setChecked(self.settings.exact_series_matches_first)
 
-        self.leKey.setText(str(self.settings.cv_api_key))
+        self.leKey.setText(self.settings.cv_api_key)
+        self.leURL.setText(self.settings.cv_url)
 
         self.cbxAssumeLoneCreditIsPrimary.setChecked(self.settings.assume_lone_credit_is_primary)
         self.cbxCopyCharactersToTags.setChecked(self.settings.copy_characters_to_tags)
@@ -303,8 +304,10 @@ class SettingsWindow(QtWidgets.QDialog):
         self.settings.sort_series_by_year = self.cbxSortByYear.isChecked()
         self.settings.exact_series_matches_first = self.cbxExactMatches.isChecked()
 
-        self.settings.cv_api_key = str(self.leKey.text())
-        ComicVineTalker.api_key = self.settings.cv_api_key.strip()
+        self.settings.cv_api_key = self.leKey.text().strip()
+        ComicVineTalker.api_key = self.settings.cv_api_key
+        self.settings.cv_url = self.leURL.text().strip()
+        ComicVineTalker.api_base_url = self.settings.cv_url
         self.settings.assume_lone_credit_is_primary = self.cbxAssumeLoneCreditIsPrimary.isChecked()
         self.settings.copy_characters_to_tags = self.cbxCopyCharactersToTags.isChecked()
         self.settings.copy_teams_to_tags = self.cbxCopyTeamsToTags.isChecked()
@@ -336,7 +339,7 @@ class SettingsWindow(QtWidgets.QDialog):
         QtWidgets.QMessageBox.information(self, self.name, "Cache has been cleared.")
 
     def test_api_key(self) -> None:
-        if ComicVineTalker().test_key(str(self.leKey.text()).strip()):
+        if ComicVineTalker().test_key(self.leKey.text().strip(), self.leURL.text().strip()):
             QtWidgets.QMessageBox.information(self, "API Key Test", "Key is valid!")
         else:
             QtWidgets.QMessageBox.warning(self, "API Key Test", "Key is NOT valid.")
diff --git a/comictaggerlib/ui/settingswindow.ui b/comictaggerlib/ui/settingswindow.ui
index b489ee3..6f5f03b 100644
--- a/comictaggerlib/ui/settingswindow.ui
+++ b/comictaggerlib/ui/settingswindow.ui
@@ -7,7 +7,7 @@
     <x>0</x>
     <y>0</y>
     <width>702</width>
-    <height>478</height>
+    <height>488</height>
    </rect>
   </property>
   <property name="windowTitle">
@@ -370,44 +370,6 @@
             </sizepolicy>
            </property>
            <layout class="QGridLayout" name="gridLayout_8">
-            <item row="1" column="1">
-             <widget class="QLineEdit" name="leKey">
-              <property name="sizePolicy">
-               <sizepolicy hsizetype="MinimumExpanding" vsizetype="Maximum">
-                <horstretch>0</horstretch>
-                <verstretch>0</verstretch>
-               </sizepolicy>
-              </property>
-              <property name="readOnly">
-               <bool>false</bool>
-              </property>
-             </widget>
-            </item>
-            <item row="1" column="0">
-             <widget class="QLabel" name="label_8">
-              <property name="sizePolicy">
-               <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
-                <horstretch>0</horstretch>
-                <verstretch>0</verstretch>
-               </sizepolicy>
-              </property>
-              <property name="minimumSize">
-               <size>
-                <width>120</width>
-                <height>0</height>
-               </size>
-              </property>
-              <property name="maximumSize">
-               <size>
-                <width>200</width>
-                <height>16777215</height>
-               </size>
-              </property>
-              <property name="text">
-               <string>Comic Vine API Key</string>
-              </property>
-             </widget>
-            </item>
             <item row="0" column="0" colspan="3">
              <widget class="QLabel" name="lblKeyHelp">
               <property name="sizePolicy">
@@ -443,6 +405,54 @@
               </property>
              </widget>
             </item>
+            <item row="1" column="1">
+             <widget class="QLineEdit" name="leKey">
+              <property name="sizePolicy">
+               <sizepolicy hsizetype="MinimumExpanding" vsizetype="Maximum">
+                <horstretch>0</horstretch>
+                <verstretch>0</verstretch>
+               </sizepolicy>
+              </property>
+              <property name="readOnly">
+               <bool>false</bool>
+              </property>
+             </widget>
+            </item>
+            <item row="1" column="0">
+             <widget class="QLabel" name="lblKey">
+              <property name="sizePolicy">
+               <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+                <horstretch>0</horstretch>
+                <verstretch>0</verstretch>
+               </sizepolicy>
+              </property>
+              <property name="minimumSize">
+               <size>
+                <width>120</width>
+                <height>0</height>
+               </size>
+              </property>
+              <property name="maximumSize">
+               <size>
+                <width>200</width>
+                <height>16777215</height>
+               </size>
+              </property>
+              <property name="text">
+               <string>Comic Vine API Key</string>
+              </property>
+             </widget>
+            </item>
+            <item row="2" column="0">
+             <widget class="QLabel" name="lblURL">
+              <property name="text">
+               <string>Comic Vine URL</string>
+              </property>
+             </widget>
+            </item>
+            <item row="2" column="1">
+             <widget class="QLineEdit" name="leURL"/>
+            </item>
            </layout>
           </widget>
          </item>