remove_fetch_alternate_cover_urls.patch
This commit is contained in:
parent
b07aa03c5f
commit
b4f6820f56
@ -180,7 +180,10 @@ class AutoTagMatchWindow(QtWidgets.QDialog):
|
||||
if prev is not None and prev.row() == curr.row():
|
||||
return None
|
||||
|
||||
self.altCoverWidget.set_issue_details(self.current_match()["issue_id"], self.current_match()["image_url"])
|
||||
self.altCoverWidget.set_issue_details(
|
||||
self.current_match()["issue_id"],
|
||||
[self.current_match()["image_url"], *self.current_match()["alt_image_urls"]],
|
||||
)
|
||||
if self.current_match()["description"] is None:
|
||||
self.teDescription.setText("")
|
||||
else:
|
||||
|
@ -20,11 +20,9 @@ TODO: This should be re-factored using subclasses!
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from typing import Callable
|
||||
|
||||
from PyQt5 import QtCore, QtGui, QtWidgets, uic
|
||||
|
||||
from comicapi import utils
|
||||
from comicapi.comicarchive import ComicArchive
|
||||
from comictaggerlib.graphics import graphics_path
|
||||
from comictaggerlib.imagefetcher import ImageFetcher
|
||||
@ -56,38 +54,14 @@ def clickable(widget: QtWidgets.QWidget) -> QtCore.pyqtBoundSignal:
|
||||
return flt.dblclicked
|
||||
|
||||
|
||||
class Signal(QtCore.QObject):
|
||||
alt_url_list_fetch_complete = QtCore.pyqtSignal(list)
|
||||
url_fetch_complete = QtCore.pyqtSignal(str, str)
|
||||
image_fetch_complete = QtCore.pyqtSignal(QtCore.QByteArray)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
list_fetch: Callable[[list[str]], None],
|
||||
url_fetch: Callable[[str, str], None],
|
||||
image_fetch: Callable[[bytes], None],
|
||||
) -> None:
|
||||
super().__init__()
|
||||
self.alt_url_list_fetch_complete.connect(list_fetch)
|
||||
self.url_fetch_complete.connect(url_fetch)
|
||||
self.image_fetch_complete.connect(image_fetch)
|
||||
|
||||
def emit_list(self, url_list: list[str]) -> None:
|
||||
self.alt_url_list_fetch_complete.emit(url_list)
|
||||
|
||||
def emit_url(self, image_url: str, thumb_url: str | None) -> None:
|
||||
self.url_fetch_complete.emit(image_url, thumb_url)
|
||||
|
||||
def emit_image(self, image_data: bytes | QtCore.QByteArray) -> None:
|
||||
self.image_fetch_complete.emit(image_data)
|
||||
|
||||
|
||||
class CoverImageWidget(QtWidgets.QWidget):
|
||||
ArchiveMode = 0
|
||||
AltCoverMode = 1
|
||||
URLMode = 1
|
||||
DataMode = 3
|
||||
|
||||
image_fetch_complete = QtCore.pyqtSignal(QtCore.QByteArray)
|
||||
|
||||
def __init__(
|
||||
self, parent: QtWidgets.QWidget, talker_api: ComicTalker, mode: int, expand_on_click: bool = True
|
||||
) -> None:
|
||||
@ -98,10 +72,6 @@ class CoverImageWidget(QtWidgets.QWidget):
|
||||
|
||||
reduce_widget_font_size(self.label)
|
||||
|
||||
self.sig = Signal(
|
||||
self.alt_cover_url_list_fetch_complete, self.primary_url_fetch_complete, self.cover_remote_fetch_complete
|
||||
)
|
||||
|
||||
self.talker_api = talker_api
|
||||
self.mode: int = mode
|
||||
self.page_loader: PageLoader | None = None
|
||||
@ -125,6 +95,7 @@ class CoverImageWidget(QtWidgets.QWidget):
|
||||
|
||||
self.btnLeft.clicked.connect(self.decrement_image)
|
||||
self.btnRight.clicked.connect(self.increment_image)
|
||||
self.image_fetch_complete.connect(self.cover_remote_fetch_complete)
|
||||
if expand_on_click:
|
||||
clickable(self.lblImage).connect(self.show_popup)
|
||||
else:
|
||||
@ -178,13 +149,13 @@ class CoverImageWidget(QtWidgets.QWidget):
|
||||
self.imageCount = 1
|
||||
self.update_content()
|
||||
|
||||
def set_issue_details(self, issue_id: int, image_url: str) -> None:
|
||||
def set_issue_details(self, issue_id: int, url_list: list[str]) -> None:
|
||||
if self.mode == CoverImageWidget.AltCoverMode:
|
||||
self.reset_widget()
|
||||
self.update_content()
|
||||
self.issue_id = issue_id
|
||||
|
||||
self.sig.emit_url(image_url, None)
|
||||
self.set_url_list(url_list)
|
||||
|
||||
def set_image_data(self, image_data: bytes) -> None:
|
||||
if self.mode == CoverImageWidget.DataMode:
|
||||
@ -198,32 +169,11 @@ class CoverImageWidget(QtWidgets.QWidget):
|
||||
|
||||
self.update_content()
|
||||
|
||||
def primary_url_fetch_complete(self, primary_url: str, thumb_url: str | None = None) -> None:
|
||||
self.url_list.append(str(primary_url))
|
||||
def set_url_list(self, url_list: list[str]) -> None:
|
||||
self.url_list = url_list
|
||||
self.imageIndex = 0
|
||||
self.imageCount = len(self.url_list)
|
||||
self.update_content()
|
||||
|
||||
# No need to search for alt covers as they are now in ComicIssue data
|
||||
if self.talker_api.static_options.has_alt_covers:
|
||||
QtCore.QTimer.singleShot(1, self.start_alt_cover_search)
|
||||
|
||||
def start_alt_cover_search(self) -> None:
|
||||
|
||||
if self.issue_id is not None:
|
||||
# now we need to get the list of alt cover URLs
|
||||
self.label.setText("Searching for alt. covers...")
|
||||
|
||||
url_list = self.talker_api.fetch_alternate_cover_urls(utils.xlate(self.issue_id))
|
||||
if url_list:
|
||||
self.url_list.extend(url_list)
|
||||
self.imageCount = len(self.url_list)
|
||||
self.update_controls()
|
||||
|
||||
def alt_cover_url_list_fetch_complete(self, url_list: list[str]) -> None:
|
||||
if url_list:
|
||||
self.url_list.extend(url_list)
|
||||
self.imageCount = len(self.url_list)
|
||||
self.update_controls()
|
||||
|
||||
def set_page(self, pagenum: int) -> None:
|
||||
@ -273,10 +223,10 @@ class CoverImageWidget(QtWidgets.QWidget):
|
||||
def load_url(self) -> None:
|
||||
self.load_default()
|
||||
self.cover_fetcher = ImageFetcher()
|
||||
ImageFetcher.image_fetch_complete = self.sig.emit_image
|
||||
ImageFetcher.image_fetch_complete = self.image_fetch_complete.emit
|
||||
self.cover_fetcher.fetch(self.url_list[self.imageIndex])
|
||||
# TODO: Figure out async
|
||||
self.sig.emit_image(self.cover_fetcher.fetch(self.url_list[self.imageIndex]))
|
||||
# self.sig.emit_image(self.cover_fetcher.fetch(self.url_list[self.imageIndex]))
|
||||
|
||||
# called when the image is done loading from internet
|
||||
def cover_remote_fetch_complete(self, image_data: bytes) -> None:
|
||||
|
@ -81,8 +81,8 @@ class ImageFetcher:
|
||||
|
||||
# first look in the DB
|
||||
image_data = self.get_image_from_cache(url)
|
||||
# TODO: figure out async
|
||||
if True: # if blocking or not qt_available:
|
||||
# Async for retrieving covers seems to work well
|
||||
if blocking: # if blocking or not qt_available:
|
||||
if not image_data:
|
||||
try:
|
||||
image_data = requests.get(url, headers={"user-agent": "comictagger/" + ctversion.version}).content
|
||||
|
@ -243,7 +243,7 @@ class IssueIdentifier:
|
||||
issue_id: int,
|
||||
primary_img_url: str,
|
||||
primary_thumb_url: str,
|
||||
page_url: str,
|
||||
alt_urls: list[str],
|
||||
local_cover_hash_list: list[int],
|
||||
use_remote_alternates: bool = False,
|
||||
use_log: bool = True,
|
||||
@ -270,8 +270,7 @@ class IssueIdentifier:
|
||||
raise IssueIdentifierCancelled
|
||||
|
||||
if use_remote_alternates:
|
||||
alt_img_url_list = self.talker_api.fetch_alternate_cover_urls(issue_id)
|
||||
for alt_url in alt_img_url_list:
|
||||
for alt_url in alt_urls:
|
||||
try:
|
||||
alt_url_image_data = ImageFetcher().fetch(alt_url, blocking=True)
|
||||
except ImageFetcherException as e:
|
||||
@ -395,10 +394,7 @@ class IssueIdentifier:
|
||||
if int(keys["year"]) < int(item["start_year"]):
|
||||
date_approved = False
|
||||
|
||||
aliases = []
|
||||
if item["aliases"]:
|
||||
aliases = item["aliases"].split("\n")
|
||||
for name in [item["name"], *aliases]:
|
||||
for name in [item["name"], *item["aliases"]]:
|
||||
if utils.titles_match(keys["series"], name, self.series_match_thresh):
|
||||
length_approved = True
|
||||
break
|
||||
@ -429,13 +425,12 @@ class IssueIdentifier:
|
||||
try:
|
||||
image_url = series["image_url"]
|
||||
thumb_url = series["image_url"]
|
||||
page_url = ""
|
||||
|
||||
score_item = self.get_issue_cover_match_score(
|
||||
series["id"],
|
||||
image_url,
|
||||
thumb_url,
|
||||
page_url, # Only required for alt covers
|
||||
[], # Only required for alt covers
|
||||
hash_list,
|
||||
use_remote_alternates=False,
|
||||
)
|
||||
@ -457,7 +452,7 @@ class IssueIdentifier:
|
||||
"publisher": series["publisher"],
|
||||
"image_url": image_url,
|
||||
"thumb_url": thumb_url,
|
||||
"page_url": page_url,
|
||||
"alt_image_urls": [],
|
||||
"description": series["description"],
|
||||
}
|
||||
|
||||
@ -525,12 +520,13 @@ class IssueIdentifier:
|
||||
image_url = issue["image_url"]
|
||||
thumb_url = issue["image_thumb_url"]
|
||||
page_url = issue["site_detail_url"]
|
||||
alt_urls = issue["alt_image_urls"]
|
||||
|
||||
score_item = self.get_issue_cover_match_score(
|
||||
issue["id"],
|
||||
image_url,
|
||||
thumb_url,
|
||||
page_url,
|
||||
alt_urls,
|
||||
hash_list,
|
||||
use_remote_alternates=False,
|
||||
)
|
||||
@ -553,6 +549,7 @@ class IssueIdentifier:
|
||||
"image_url": image_url,
|
||||
"thumb_url": thumb_url,
|
||||
"page_url": page_url,
|
||||
"alt_image_urls": alt_urls,
|
||||
"description": issue["description"],
|
||||
}
|
||||
if series["publisher"] is not None:
|
||||
@ -617,11 +614,12 @@ class IssueIdentifier:
|
||||
m["issue_id"],
|
||||
m["image_url"],
|
||||
m["thumb_url"],
|
||||
m["page_url"],
|
||||
m["alt_image_urls"],
|
||||
hash_list,
|
||||
use_remote_alternates=True,
|
||||
)
|
||||
except Exception:
|
||||
logger.exception("failed examining alt covers")
|
||||
self.match_list = []
|
||||
return self.match_list
|
||||
self.log_msg(f"--->{score_item['score']}")
|
||||
|
@ -180,7 +180,7 @@ class IssueSelectionWindow(QtWidgets.QDialog):
|
||||
for record in self.issue_list:
|
||||
if record["id"] == self.issue_id:
|
||||
self.issue_number = record["issue_number"]
|
||||
self.coverWidget.set_issue_details(self.issue_id, record["image_url"])
|
||||
self.coverWidget.set_issue_details(self.issue_id, [record["image_url"], *record["alt_image_urls"]])
|
||||
if record["description"] is None:
|
||||
self.teDescription.setText("")
|
||||
else:
|
||||
|
@ -149,7 +149,10 @@ class MatchSelectionWindow(QtWidgets.QDialog):
|
||||
if prev is not None and prev.row() == curr.row():
|
||||
return
|
||||
|
||||
self.altCoverWidget.set_issue_details(self.current_match()["issue_id"], self.current_match()["image_url"])
|
||||
self.altCoverWidget.set_issue_details(
|
||||
self.current_match()["issue_id"],
|
||||
[self.current_match()["image_url"], *self.current_match()["alt_image_urls"]],
|
||||
)
|
||||
if self.current_match()["description"] is None:
|
||||
self.teDescription.setText("")
|
||||
else:
|
||||
|
@ -19,7 +19,7 @@ class IssueResult(TypedDict):
|
||||
publisher: str | None
|
||||
image_url: str
|
||||
thumb_url: str
|
||||
page_url: str
|
||||
alt_image_urls: list[str]
|
||||
description: str
|
||||
|
||||
|
||||
|
@ -170,7 +170,6 @@ class VolumeSelectionWindow(QtWidgets.QDialog):
|
||||
self.cbxFilter.toggled.connect(self.filter_toggled)
|
||||
|
||||
self.update_buttons()
|
||||
self.perform_query()
|
||||
self.twList.selectRow(0)
|
||||
|
||||
def update_buttons(self) -> None:
|
||||
@ -331,18 +330,23 @@ class VolumeSelectionWindow(QtWidgets.QDialog):
|
||||
|
||||
def perform_query(self, refresh: bool = False) -> None:
|
||||
|
||||
self.progdialog = QtWidgets.QProgressDialog("Searching Online", "Cancel", 0, 100, self)
|
||||
self.progdialog.setWindowTitle("Online Search")
|
||||
self.progdialog.canceled.connect(self.search_canceled)
|
||||
self.progdialog.setModal(True)
|
||||
self.progdialog.setMinimumDuration(300)
|
||||
self.search_thread = SearchThread(
|
||||
self.talker_api, 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()
|
||||
self.progdialog.exec()
|
||||
|
||||
self.progdialog = QtWidgets.QProgressDialog("Searching Online", "Cancel", 0, 100, self)
|
||||
self.progdialog.setWindowTitle("Online Search")
|
||||
self.progdialog.canceled.connect(self.search_canceled)
|
||||
self.progdialog.setModal(True)
|
||||
self.progdialog.setMinimumDuration(300)
|
||||
|
||||
if refresh or self.search_thread.isRunning():
|
||||
self.progdialog.exec()
|
||||
else:
|
||||
self.progdialog = None
|
||||
|
||||
def search_canceled(self) -> None:
|
||||
if self.progdialog is not None:
|
||||
@ -365,122 +369,123 @@ class VolumeSelectionWindow(QtWidgets.QDialog):
|
||||
def search_complete(self) -> None:
|
||||
if self.progdialog is not None:
|
||||
self.progdialog.accept()
|
||||
del self.progdialog
|
||||
if self.search_thread is not None and self.search_thread.ct_error:
|
||||
# TODO Currently still opens the window
|
||||
QtWidgets.QMessageBox.critical(
|
||||
self,
|
||||
f"{self.search_thread.error_e.source} {self.search_thread.error_e.code_name} Error",
|
||||
f"{self.search_thread.error_e}",
|
||||
)
|
||||
return
|
||||
self.progdialog = None
|
||||
if self.search_thread is not None and self.search_thread.ct_error:
|
||||
# TODO Currently still opens the window
|
||||
QtWidgets.QMessageBox.critical(
|
||||
self,
|
||||
f"{self.search_thread.error_e.source} {self.search_thread.error_e.code_name} Error",
|
||||
f"{self.search_thread.error_e}",
|
||||
)
|
||||
return
|
||||
|
||||
self.ct_search_results = self.search_thread.ct_search_results if self.search_thread is not None else []
|
||||
# filter the publishers if enabled set
|
||||
if self.use_filter:
|
||||
try:
|
||||
publisher_filter = {s.strip().casefold() for s in self.settings.id_publisher_filter.split(",")}
|
||||
# use '' as publisher name if None
|
||||
self.ct_search_results = list(
|
||||
filter(
|
||||
lambda d: ("" if d["publisher"] is None else str(d["publisher"]).casefold())
|
||||
not in publisher_filter,
|
||||
self.ct_search_results,
|
||||
)
|
||||
)
|
||||
except Exception:
|
||||
logger.exception("bad data error filtering publishers")
|
||||
|
||||
# pre sort the data - so that we can put exact matches first afterwards
|
||||
# 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.settings.sort_series_by_year:
|
||||
try:
|
||||
self.ct_search_results = sorted(
|
||||
self.ct_search_results = self.search_thread.ct_search_results if self.search_thread is not None else []
|
||||
# filter the publishers if enabled set
|
||||
if self.use_filter:
|
||||
try:
|
||||
publisher_filter = {s.strip().casefold() for s in self.settings.id_publisher_filter.split(",")}
|
||||
# use '' as publisher name if None
|
||||
self.ct_search_results = list(
|
||||
filter(
|
||||
lambda d: ("" if d["publisher"] is None else str(d["publisher"]).casefold())
|
||||
not in publisher_filter,
|
||||
self.ct_search_results,
|
||||
key=lambda i: (str(i["start_year"]), str(i["count_of_issues"])),
|
||||
reverse=True,
|
||||
)
|
||||
except Exception:
|
||||
logger.exception("bad data error sorting results by start_year,count_of_issues")
|
||||
else:
|
||||
try:
|
||||
self.ct_search_results = sorted(
|
||||
self.ct_search_results, key=lambda i: str(i["count_of_issues"]), reverse=True
|
||||
)
|
||||
except Exception:
|
||||
logger.exception("bad data error sorting results by count_of_issues")
|
||||
)
|
||||
except Exception:
|
||||
logger.exception("bad data error filtering publishers")
|
||||
|
||||
# move sanitized matches to the front
|
||||
if self.settings.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()
|
||||
# pre sort the data - so that we can put exact matches first afterwards
|
||||
# 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.settings.sort_series_by_year:
|
||||
try:
|
||||
self.ct_search_results = sorted(
|
||||
self.ct_search_results,
|
||||
key=lambda i: (str(i["start_year"]), str(i["count_of_issues"])),
|
||||
reverse=True,
|
||||
)
|
||||
except Exception:
|
||||
logger.exception("bad data error sorting results by start_year,count_of_issues")
|
||||
else:
|
||||
try:
|
||||
self.ct_search_results = sorted(
|
||||
self.ct_search_results, key=lambda i: str(i["count_of_issues"]), reverse=True
|
||||
)
|
||||
except Exception:
|
||||
logger.exception("bad data error sorting results by count_of_issues")
|
||||
|
||||
deques: list[deque[ComicVolume]] = [deque(), deque(), deque()]
|
||||
# move sanitized matches to the front
|
||||
if self.settings.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()
|
||||
|
||||
def categorize(result: ComicVolume) -> int:
|
||||
# We don't remove anything on this one so that we only get exact matches
|
||||
if utils.sanitize_title(result["name"], True).casefold() == sanitized_no_articles:
|
||||
return 0
|
||||
deques: list[deque[ComicVolume]] = [deque(), deque(), deque()]
|
||||
|
||||
# this ensures that 'The Joker' is near the top even if you search 'Joker'
|
||||
if utils.sanitize_title(result["name"], False).casefold() in sanitized:
|
||||
return 1
|
||||
return 2
|
||||
def categorize(result: ComicVolume) -> int:
|
||||
# We don't remove anything on this one so that we only get exact matches
|
||||
if utils.sanitize_title(result["name"], True).casefold() == sanitized_no_articles:
|
||||
return 0
|
||||
|
||||
for comic in self.ct_search_results:
|
||||
deques[categorize(comic)].append(comic)
|
||||
logger.info("Length: %d, %d, %d", len(deques[0]), len(deques[1]), len(deques[2]))
|
||||
self.ct_search_results = list(itertools.chain.from_iterable(deques))
|
||||
except Exception:
|
||||
logger.exception("bad data error filtering exact/near matches")
|
||||
# this ensures that 'The Joker' is near the top even if you search 'Joker'
|
||||
if utils.sanitize_title(result["name"], False).casefold() in sanitized:
|
||||
return 1
|
||||
return 2
|
||||
|
||||
self.update_buttons()
|
||||
for comic in self.ct_search_results:
|
||||
deques[categorize(comic)].append(comic)
|
||||
logger.info("Length: %d, %d, %d", len(deques[0]), len(deques[1]), len(deques[2]))
|
||||
self.ct_search_results = list(itertools.chain.from_iterable(deques))
|
||||
except Exception:
|
||||
logger.exception("bad data error filtering exact/near matches")
|
||||
|
||||
self.twList.setSortingEnabled(False)
|
||||
self.update_buttons()
|
||||
|
||||
self.twList.setRowCount(0)
|
||||
self.twList.setSortingEnabled(False)
|
||||
|
||||
row = 0
|
||||
for record in self.ct_search_results:
|
||||
self.twList.insertRow(row)
|
||||
self.twList.setRowCount(0)
|
||||
|
||||
item_text = record["name"]
|
||||
item = QtWidgets.QTableWidgetItem(item_text)
|
||||
row = 0
|
||||
for record in self.ct_search_results:
|
||||
self.twList.insertRow(row)
|
||||
|
||||
item_text = record["name"]
|
||||
item = QtWidgets.QTableWidgetItem(item_text)
|
||||
item.setData(QtCore.Qt.ItemDataRole.ToolTipRole, item_text)
|
||||
item.setData(QtCore.Qt.ItemDataRole.UserRole, record["id"])
|
||||
item.setFlags(QtCore.Qt.ItemFlag.ItemIsSelectable | QtCore.Qt.ItemFlag.ItemIsEnabled)
|
||||
self.twList.setItem(row, 0, item)
|
||||
|
||||
item_text = str(record["start_year"])
|
||||
item = QtWidgets.QTableWidgetItem(item_text)
|
||||
item.setData(QtCore.Qt.ItemDataRole.ToolTipRole, item_text)
|
||||
item.setFlags(QtCore.Qt.ItemFlag.ItemIsSelectable | QtCore.Qt.ItemFlag.ItemIsEnabled)
|
||||
self.twList.setItem(row, 1, item)
|
||||
|
||||
item_text = str(record["count_of_issues"])
|
||||
item = QtWidgets.QTableWidgetItem(item_text)
|
||||
item.setData(QtCore.Qt.ItemDataRole.ToolTipRole, item_text)
|
||||
item.setData(QtCore.Qt.ItemDataRole.DisplayRole, record["count_of_issues"])
|
||||
item.setFlags(QtCore.Qt.ItemFlag.ItemIsSelectable | QtCore.Qt.ItemFlag.ItemIsEnabled)
|
||||
self.twList.setItem(row, 2, item)
|
||||
|
||||
if record["publisher"] is not None:
|
||||
item_text = record["publisher"]
|
||||
item.setData(QtCore.Qt.ItemDataRole.ToolTipRole, item_text)
|
||||
item.setData(QtCore.Qt.ItemDataRole.UserRole, record["id"])
|
||||
item.setFlags(QtCore.Qt.ItemFlag.ItemIsSelectable | QtCore.Qt.ItemFlag.ItemIsEnabled)
|
||||
self.twList.setItem(row, 0, item)
|
||||
|
||||
item_text = str(record["start_year"])
|
||||
item = QtWidgets.QTableWidgetItem(item_text)
|
||||
item.setData(QtCore.Qt.ItemDataRole.ToolTipRole, item_text)
|
||||
item.setFlags(QtCore.Qt.ItemFlag.ItemIsSelectable | QtCore.Qt.ItemFlag.ItemIsEnabled)
|
||||
self.twList.setItem(row, 1, item)
|
||||
self.twList.setItem(row, 3, item)
|
||||
|
||||
item_text = str(record["count_of_issues"])
|
||||
item = QtWidgets.QTableWidgetItem(item_text)
|
||||
item.setData(QtCore.Qt.ItemDataRole.ToolTipRole, item_text)
|
||||
item.setData(QtCore.Qt.ItemDataRole.DisplayRole, record["count_of_issues"])
|
||||
item.setFlags(QtCore.Qt.ItemFlag.ItemIsSelectable | QtCore.Qt.ItemFlag.ItemIsEnabled)
|
||||
self.twList.setItem(row, 2, item)
|
||||
row += 1
|
||||
|
||||
if record["publisher"] is not None:
|
||||
item_text = record["publisher"]
|
||||
item.setData(QtCore.Qt.ItemDataRole.ToolTipRole, item_text)
|
||||
item = QtWidgets.QTableWidgetItem(item_text)
|
||||
item.setFlags(QtCore.Qt.ItemFlag.ItemIsSelectable | QtCore.Qt.ItemFlag.ItemIsEnabled)
|
||||
self.twList.setItem(row, 3, item)
|
||||
|
||||
row += 1
|
||||
|
||||
self.twList.setSortingEnabled(True)
|
||||
self.twList.selectRow(0)
|
||||
self.twList.resizeColumnsToContents()
|
||||
self.twList.setSortingEnabled(True)
|
||||
self.twList.selectRow(0)
|
||||
self.twList.resizeColumnsToContents()
|
||||
|
||||
def showEvent(self, event: QtGui.QShowEvent) -> None:
|
||||
self.perform_query()
|
||||
if not self.ct_search_results:
|
||||
QtCore.QCoreApplication.processEvents()
|
||||
QtWidgets.QMessageBox.information(self, "Search Result", "No matches found!")
|
||||
|
@ -111,7 +111,7 @@ class ComicCacher:
|
||||
+ "timestamp DATE DEFAULT (datetime('now','localtime')), "
|
||||
+ "source_name TEXT NOT NULL,"
|
||||
+ "aliases TEXT," # Newline separated
|
||||
+ "alt_images_url TEXT," # Comma separated URLs
|
||||
+ "alt_image_urls TEXT," # Newline separated URLs
|
||||
+ "characters TEXT," # Newline separated
|
||||
+ "locations TEXT," # Newline separated
|
||||
+ "credits TEXT," # JSON: "{"name": "Bob Shakespeare", "role": "Writer"}"
|
||||
@ -146,10 +146,17 @@ class ComicCacher:
|
||||
)
|
||||
|
||||
data = {
|
||||
"id": record["id"],
|
||||
"source_name": source_name,
|
||||
"name": record["name"],
|
||||
"publisher": record["publisher"],
|
||||
"count_of_issues": record["count_of_issues"],
|
||||
"image_url": record["image_url"],
|
||||
"start_year": record["start_year"],
|
||||
"description": record["description"],
|
||||
"timestamp": datetime.datetime.now(),
|
||||
"aliases": "\n".join(record["aliases"]),
|
||||
}
|
||||
data.update(record)
|
||||
self.upsert(cur, "volumes", data)
|
||||
|
||||
def get_search_results(self, source_name: str, search_term: str) -> list[ComicVolume]:
|
||||
@ -176,7 +183,7 @@ class ComicCacher:
|
||||
count_of_issues=record[7],
|
||||
start_year=record[8],
|
||||
image_url=record[9],
|
||||
aliases=record[10],
|
||||
aliases=record[10].split("\n"),
|
||||
description=record[11],
|
||||
)
|
||||
|
||||
@ -201,7 +208,7 @@ class ComicCacher:
|
||||
"count_of_issues": volume_record["count_of_issues"],
|
||||
"start_year": volume_record["start_year"],
|
||||
"timestamp": timestamp,
|
||||
"aliases": volume_record["aliases"],
|
||||
"aliases": "\n".join(volume_record["aliases"]),
|
||||
}
|
||||
self.upsert(cur, "volumes", data)
|
||||
|
||||
@ -228,8 +235,8 @@ class ComicCacher:
|
||||
"thumb_url": issue["image_thumb_url"],
|
||||
"description": issue["description"],
|
||||
"timestamp": timestamp,
|
||||
"aliases": issue["aliases"],
|
||||
"alt_images_url": issue["alt_images_url"],
|
||||
"aliases": "\n".join(issue["aliases"]),
|
||||
"alt_image_urls": "\n".join(issue["alt_image_urls"]),
|
||||
"characters": "\n".join(issue["characters"]),
|
||||
"locations": "\n".join(issue["locations"]),
|
||||
"teams": "\n".join(issue["teams"]),
|
||||
@ -295,7 +302,7 @@ class ComicCacher:
|
||||
|
||||
cur.execute(
|
||||
(
|
||||
"SELECT source_name,id,name,issue_number,site_detail_url,cover_date,image_url,thumb_url,description,aliases,alt_images_url,characters,locations,credits,teams,story_arcs,complete"
|
||||
"SELECT source_name,id,name,issue_number,site_detail_url,cover_date,image_url,thumb_url,description,aliases,alt_image_urls,characters,locations,credits,teams,story_arcs,complete"
|
||||
" FROM Issues WHERE volume_id=? AND source_name=?"
|
||||
),
|
||||
[volume_id, source_name],
|
||||
@ -314,7 +321,7 @@ class ComicCacher:
|
||||
description=row[8],
|
||||
volume=volume,
|
||||
aliases=row[9],
|
||||
alt_images_url=row[10],
|
||||
alt_image_urls=row[10].split("\n"),
|
||||
characters=row[11].split("\n"),
|
||||
locations=row[12].split("\n"),
|
||||
credits=json.loads(row[13]),
|
||||
@ -340,7 +347,7 @@ class ComicCacher:
|
||||
|
||||
cur.execute(
|
||||
(
|
||||
"SELECT source_name,id,name,issue_number,site_detail_url,cover_date,image_url,thumb_url,description,aliases,volume_id,alt_images_url,characters,locations,credits,teams,story_arcs,complete"
|
||||
"SELECT source_name,id,name,issue_number,site_detail_url,cover_date,image_url,thumb_url,description,aliases,volume_id,alt_image_urls,characters,locations,credits,teams,story_arcs,complete"
|
||||
" FROM Issues WHERE id=? AND source_name=?"
|
||||
),
|
||||
[issue_id, source_name],
|
||||
@ -366,7 +373,7 @@ class ComicCacher:
|
||||
description=row[8],
|
||||
volume=volume,
|
||||
aliases=row[9],
|
||||
alt_images_url=row[11],
|
||||
alt_image_urls=row[11].split("\n"),
|
||||
characters=row[12].split("\n"),
|
||||
locations=row[13].split("\n"),
|
||||
credits=json.loads(row[14]),
|
||||
|
@ -9,7 +9,7 @@ class Credits(TypedDict):
|
||||
|
||||
|
||||
class ComicVolume(TypedDict, total=False):
|
||||
aliases: str # Newline separated
|
||||
aliases: list[str]
|
||||
count_of_issues: int
|
||||
description: str
|
||||
id: Required[int]
|
||||
@ -20,7 +20,7 @@ class ComicVolume(TypedDict, total=False):
|
||||
|
||||
|
||||
class ComicIssue(TypedDict, total=False):
|
||||
aliases: str # Newline separated
|
||||
aliases: list[str]
|
||||
cover_date: str
|
||||
description: str
|
||||
id: int
|
||||
@ -30,10 +30,10 @@ class ComicIssue(TypedDict, total=False):
|
||||
name: Required[str]
|
||||
site_detail_url: str
|
||||
volume: ComicVolume
|
||||
alt_images_url: str # Comma separated URLs
|
||||
characters: list
|
||||
locations: list
|
||||
alt_image_urls: list[str]
|
||||
characters: list[str]
|
||||
locations: list[str]
|
||||
credits: list[Credits]
|
||||
teams: list
|
||||
story_arcs: list
|
||||
complete: bool # Is the data complete? Includes characters, locations, credits.
|
||||
teams: list[str]
|
||||
story_arcs: list[str]
|
||||
complete: bool # Is this a complete ComicIssue? or is there more data to fetch
|
||||
|
@ -186,10 +186,6 @@ class ComicTalker:
|
||||
3. Only issue_id. Retrieve the ISSUE information."""
|
||||
raise NotImplementedError
|
||||
|
||||
# TODO Should be able to remove with alt cover rework
|
||||
def fetch_alternate_cover_urls(self, issue_id: int) -> list[str]:
|
||||
raise NotImplementedError
|
||||
|
||||
def fetch_issues_by_volume_issue_num_and_year(
|
||||
self, volume_id_list: list[int], issue_number: str, year: str | int | None
|
||||
) -> list[ComicIssue]:
|
||||
|
@ -376,10 +376,11 @@ class ComicVineTalker(ComicTalker):
|
||||
start_year = 0
|
||||
else:
|
||||
start_year = utils.xlate(record["start_year"], True)
|
||||
aliases = record["aliases"] or ""
|
||||
|
||||
formatted_results.append(
|
||||
ComicVolume(
|
||||
aliases=record["aliases"],
|
||||
aliases=aliases.split("\n"),
|
||||
count_of_issues=record.get("count_of_issues", 0),
|
||||
description=record.get("description", ""),
|
||||
id=record["id"],
|
||||
@ -410,7 +411,7 @@ class ComicVineTalker(ComicTalker):
|
||||
# Convert to comma separated
|
||||
alt_images_list.append(alt["original_url"])
|
||||
|
||||
alt_images_url = ",".join(alt_images_list)
|
||||
alt_image_urls = alt_images_list
|
||||
|
||||
character_list = []
|
||||
if record.get("character_credits"):
|
||||
@ -439,7 +440,7 @@ class ComicVineTalker(ComicTalker):
|
||||
|
||||
formatted_results.append(
|
||||
ComicIssue(
|
||||
aliases=record["aliases"],
|
||||
aliases=record["aliases"].split("\n") if record["aliases"] else [],
|
||||
cover_date=record.get("cover_date", ""),
|
||||
description=record.get("description", ""),
|
||||
id=record["id"],
|
||||
@ -449,7 +450,7 @@ class ComicVineTalker(ComicTalker):
|
||||
name=record["name"],
|
||||
site_detail_url=record.get("site_detail_url", ""),
|
||||
volume=cast(ComicVolume, record["volume"]),
|
||||
alt_images_url=alt_images_url,
|
||||
alt_image_urls=alt_image_urls,
|
||||
characters=character_list,
|
||||
locations=location_list,
|
||||
teams=teams_list,
|
||||
@ -957,35 +958,6 @@ class ComicVineTalker(ComicTalker):
|
||||
|
||||
return newstring
|
||||
|
||||
def fetch_alternate_cover_urls(self, issue_id: int) -> list[str]:
|
||||
# Should always be in cache
|
||||
cvc = ComicCacher()
|
||||
issue = cvc.get_issue_info(issue_id, self.source_name)
|
||||
|
||||
if issue:
|
||||
url_list = [x for x in issue["alt_images_url"].split(",") if x] # Prevent an empty string producing ['']
|
||||
else:
|
||||
# On the off chance it is not in cache
|
||||
params = {
|
||||
"api_key": self.api_key,
|
||||
"filter": f"id:{issue_id}",
|
||||
"format": "json",
|
||||
"field_list": "id,volume,issue_number,name,image,cover_date,site_detail_url,description,aliases,associated_images",
|
||||
"offset": 0,
|
||||
}
|
||||
cv_response = self.get_cv_content(urljoin(self.api_base_url, "issues/"), params)
|
||||
|
||||
issue_result = cast(list[CVIssueDetailResults], cv_response["results"])
|
||||
|
||||
# Format to expected output
|
||||
formatted_volume_issues_result = self.format_issue_results(issue_result)
|
||||
|
||||
cvc.add_volume_issues_info(self.source_name, formatted_volume_issues_result)
|
||||
|
||||
url_list = [x for x in formatted_volume_issues_result[0]["alt_images_url"].split(",") if x]
|
||||
|
||||
return url_list
|
||||
|
||||
def repair_urls(self, issue_list: list[CVIssueDetailResults]) -> None:
|
||||
# make sure there are URLs for the image fields
|
||||
for issue in issue_list:
|
||||
|
@ -13,7 +13,7 @@ search_results = [
|
||||
name="test",
|
||||
publisher="test",
|
||||
start_year=0,
|
||||
aliases="",
|
||||
aliases=[],
|
||||
),
|
||||
comictalker.resulttypes.ComicVolume(
|
||||
count_of_issues=1,
|
||||
@ -23,7 +23,7 @@ search_results = [
|
||||
name="test 2",
|
||||
publisher="test",
|
||||
start_year=0,
|
||||
aliases="",
|
||||
aliases=[],
|
||||
),
|
||||
]
|
||||
|
||||
|
@ -62,7 +62,7 @@ def test_fetch_issues_by_volume_issue_num_and_year(comicvine_api):
|
||||
for r, e in zip(results, [cv_expected]):
|
||||
del r["image_thumb_url"]
|
||||
del r["image_url"]
|
||||
del r["alt_images_url"]
|
||||
del r["alt_image_urls"]
|
||||
del r["characters"]
|
||||
del r["credits"]
|
||||
del r["locations"]
|
||||
|
Loading…
Reference in New Issue
Block a user