remove_fetch_alternate_cover_urls.patch

This commit is contained in:
Mizaki 2022-11-03 23:32:35 +00:00
parent b07aa03c5f
commit b4f6820f56
14 changed files with 172 additions and 238 deletions

View File

@ -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:

View File

@ -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:

View File

@ -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

View File

@ -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']}")

View File

@ -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:

View File

@ -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:

View File

@ -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

View File

@ -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!")

View File

@ -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]),

View File

@ -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

View File

@ -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]:

View File

@ -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:

View File

@ -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=[],
),
]

View File

@ -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"]