Compare commits

...

16 Commits

Author SHA1 Message Date
2e2d886cb2 Bump settngs 2024-02-22 14:52:26 -08:00
5738433c2b Fix fileselectionlist
Remove the custom widgetitem
Set a minimum size for the columns
Use a space " " a and nbsp "\xa0" for the check column to allow sorting
2024-02-22 14:30:15 -08:00
4a33dbde46 Fix PyInstaller packaging 2024-02-22 14:30:15 -08:00
10a48634bd Update talker dependencies 2024-02-19 12:29:36 -08:00
2492d96fb3 Merge branch 'pre-commit-ci-update-config' into develop 2024-02-19 12:08:43 -08:00
87248503b4 Allow 7z again 2024-02-19 11:57:30 -08:00
7705e7ea1f [pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/asottile/pyupgrade: v3.15.0 → v3.15.1](https://github.com/asottile/pyupgrade/compare/v3.15.0...v3.15.1)
- [github.com/PyCQA/autoflake: v2.2.1 → v2.3.0](https://github.com/PyCQA/autoflake/compare/v2.2.1...v2.3.0)
- [github.com/psf/black: 24.1.1 → 24.2.0](https://github.com/psf/black/compare/24.1.1...24.2.0)
2024-02-19 17:19:25 +00:00
54b0630891 Allow 7z for rar decompression on Windows 2024-02-18 21:57:51 -08:00
27e70b966f Export translator_synonyms 2024-02-18 21:39:27 -08:00
ad8b92743c Remove unused variable 2024-02-18 18:01:51 -08:00
22b44c87ca Merge branch 'mizaki/autotag_source' into develop 2024-02-18 18:00:09 -08:00
2eca743f20 Fix #602
Tests were not made correctly to catch the change in 2c3a2566cc
This has now been corrected
2024-02-18 17:31:00 -08:00
bb4be306cc Fix fileselectionlist columns 2024-02-18 17:28:55 -08:00
768ef0b6bc Fix rar exe handling 2024-02-18 01:40:49 -08:00
215587d9a4 Move path under progress bar 2024-02-17 18:38:51 +00:00
7430e59b64 Add attributation to auto tag window 2024-02-17 18:36:49 +00:00
14 changed files with 166 additions and 80 deletions

View File

@ -14,12 +14,12 @@ repos:
hooks:
- id: setup-cfg-fmt
- repo: https://github.com/asottile/pyupgrade
rev: v3.15.0
rev: v3.15.1
hooks:
- id: pyupgrade
args: [--py39-plus]
- repo: https://github.com/PyCQA/autoflake
rev: v2.2.1
rev: v2.3.0
hooks:
- id: autoflake
args: [-i, --remove-all-unused-imports, --ignore-init-module-imports]
@ -29,7 +29,7 @@ repos:
- id: isort
args: [--af,--add-import, 'from __future__ import annotations']
- repo: https://github.com/psf/black
rev: 24.1.1
rev: 24.2.0
hooks:
- id: black
- repo: https://github.com/PyCQA/flake8

View File

@ -260,7 +260,21 @@ class RarArchiver(Archiver):
return True
def is_writable(self) -> bool:
return bool(self.exe and (os.path.exists(self.exe) or shutil.which(self.exe)))
try:
if bool(self.exe and (os.path.exists(self.exe) or shutil.which(self.exe))):
return (
subprocess.run(
(self.exe,),
startupinfo=self.startupinfo,
capture_output=True,
cwd=self.path.absolute().parent,
)
.stdout.strip()
.startswith(b"RAR")
)
except OSError:
...
return False
def extension(self) -> str:
return ".cbr"
@ -271,7 +285,19 @@ class RarArchiver(Archiver):
@classmethod
def is_valid(cls, path: pathlib.Path) -> bool:
if rar_support:
return rarfile.is_rarfile(str(path))
# Try using exe
orig = rarfile.UNRAR_TOOL
rarfile.UNRAR_TOOL = cls.exe
try:
return rarfile.is_rarfile(str(path)) and rarfile.tool_setup(sevenzip=False, sevenzip2=False, force=True)
except rarfile.RarCannotExec:
rarfile.UNRAR_TOOL = orig
# Fallback to standard
try:
return rarfile.is_rarfile(str(path)) and rarfile.tool_setup(force=True)
except rarfile.RarCannotExec as e:
logger.info(e)
return False
def get_rar_obj(self) -> rarfile.RarFile | None:

View File

@ -101,7 +101,7 @@ class GenericMetadata:
letterer_synonyms = ("letterer", "letters")
cover_synonyms = ("cover", "covers", "coverartist", "cover artist")
editor_synonyms = ("editor", "edits", "editing")
_translator_synonyms = ("translator", "translation")
translator_synonyms = ("translator", "translation")
is_empty: bool = True
tag_origin: TagOrigin | None = None

View File

@ -236,6 +236,14 @@ def add_to_path(dirname: str) -> None:
os.environ["PATH"] = os.pathsep.join(paths)
def remove_from_path(dirname: str) -> None:
if dirname:
dirname = os.path.abspath(dirname)
paths = [os.path.normpath(x) for x in split(os.environ["PATH"], os.pathsep) if dirname != os.path.normpath(x)]
os.environ["PATH"] = os.pathsep.join(paths)
def xlate_int(data: Any) -> int | None:
data = xlate_float(data)
if data is None:

View File

@ -1,7 +1,8 @@
from __future__ import annotations
from PyInstaller.utils.hooks import collect_data_files, collect_entry_point
from PyInstaller.utils.hooks import collect_data_files, collect_entry_point, collect_submodules
datas, hiddenimports = collect_entry_point("comictagger.talker")
hiddenimports += collect_submodules("comictaggerlib")
datas += collect_data_files("comictaggerlib.ui")
datas += collect_data_files("comictaggerlib.graphics")

View File

@ -35,6 +35,8 @@ class AutoTagProgressWindow(QtWidgets.QDialog):
with (ui_path / "autotagprogresswindow.ui").open(encoding="utf-8") as uifile:
uic.loadUi(uifile, self)
self.lblSourceName.setText(talker.attribution)
self.archiveCoverWidget = CoverImageWidget(
self.archiveCoverContainer, CoverImageWidget.DataMode, None, None, False
)

View File

@ -62,16 +62,22 @@ def register_talker_settings(manager: settngs.Manager, talkers: dict[str, ComicT
def validate_archive_settings(config: settngs.Config[ct_ns]) -> settngs.Config[ct_ns]:
if "archiver" not in config[1]:
return config
cfg = settngs.normalize_config(config, file=True, cmdline=True, default=False)
for archiver in comicapi.comicarchive.archivers:
group = group_for_plugin(archiver())
exe_name = settngs.sanitize_name(archiver.exe)
if exe_name in cfg[0][group_for_plugin(archiver())] and cfg[0][group_for_plugin(archiver())][exe_name]:
if os.path.basename(cfg[0][group_for_plugin(archiver())][exe_name]) == archiver.exe:
comicapi.utils.add_to_path(os.path.dirname(cfg[0][group_for_plugin(archiver())][exe_name]))
else:
archiver.exe = cfg[0][group_for_plugin(archiver())][exe_name]
if not exe_name:
continue
if exe_name in cfg[0][group] and cfg[0][group][exe_name]:
path = cfg[0][group][exe_name]
name = os.path.basename(path)
# If the path is not the basename then this is a relative or absolute path.
# Ensure it is absolute
if path != name:
path = os.path.abspath(path)
archiver.exe = path
return config

View File

@ -35,21 +35,15 @@ from comictaggerlib.ui.qtutils import center_window_on_parent, reduce_widget_fon
logger = logging.getLogger(__name__)
class FileTableWidgetItem(QtWidgets.QTableWidgetItem):
def __lt__(self, other: object) -> bool:
return self.data(QtCore.Qt.ItemDataRole.UserRole) < other.data(QtCore.Qt.ItemDataRole.UserRole) # type: ignore
class FileSelectionList(QtWidgets.QWidget):
selectionChanged = QtCore.pyqtSignal(QtCore.QVariant)
listCleared = QtCore.pyqtSignal()
fileColNum = 0
CRFlagColNum = 1
CBLFlagColNum = 2
typeColNum = 3
readonlyColNum = 4
folderColNum = 5
MDFlagColNum = 1
typeColNum = 2
readonlyColNum = 3
folderColNum = 4
dataColNum = fileColNum
def __init__(
@ -64,7 +58,7 @@ class FileSelectionList(QtWidgets.QWidget):
reduce_widget_font_size(self.twList)
self.twList.setColumnCount(6)
self.twList.horizontalHeader().setMinimumSectionSize(50)
self.twList.currentItemChanged.connect(self.current_item_changed_cb)
self.currentItem = None
@ -225,8 +219,7 @@ class FileSelectionList(QtWidgets.QWidget):
# Adjust column size
self.twList.resizeColumnsToContents()
self.twList.setColumnWidth(FileSelectionList.CRFlagColNum, 35)
self.twList.setColumnWidth(FileSelectionList.CBLFlagColNum, 35)
self.twList.setColumnWidth(FileSelectionList.MDFlagColNum, 35)
self.twList.setColumnWidth(FileSelectionList.readonlyColNum, 35)
self.twList.setColumnWidth(FileSelectionList.typeColNum, 45)
if self.twList.columnWidth(FileSelectionList.fileColNum) > 250:
@ -280,9 +273,8 @@ class FileSelectionList(QtWidgets.QWidget):
filename_item = QtWidgets.QTableWidgetItem()
folder_item = QtWidgets.QTableWidgetItem()
md_item = FileTableWidgetItem()
cbi_item = FileTableWidgetItem()
readonly_item = FileTableWidgetItem()
md_item = QtWidgets.QTableWidgetItem()
readonly_item = QtWidgets.QTableWidgetItem()
type_item = QtWidgets.QTableWidgetItem()
filename_item.setFlags(QtCore.Qt.ItemFlag.ItemIsSelectable | QtCore.Qt.ItemFlag.ItemIsEnabled)
@ -297,11 +289,7 @@ class FileSelectionList(QtWidgets.QWidget):
md_item.setFlags(QtCore.Qt.ItemFlag.ItemIsSelectable | QtCore.Qt.ItemFlag.ItemIsEnabled)
md_item.setTextAlignment(QtCore.Qt.AlignmentFlag.AlignHCenter)
self.twList.setItem(row, FileSelectionList.CRFlagColNum, md_item)
cbi_item.setFlags(QtCore.Qt.ItemFlag.ItemIsSelectable | QtCore.Qt.ItemFlag.ItemIsEnabled)
cbi_item.setTextAlignment(QtCore.Qt.AlignmentFlag.AlignHCenter)
self.twList.setItem(row, FileSelectionList.CBLFlagColNum, cbi_item)
self.twList.setItem(row, FileSelectionList.MDFlagColNum, md_item)
readonly_item.setFlags(QtCore.Qt.ItemFlag.ItemIsSelectable | QtCore.Qt.ItemFlag.ItemIsEnabled)
readonly_item.setTextAlignment(QtCore.Qt.AlignmentFlag.AlignHCenter)
@ -318,7 +306,7 @@ class FileSelectionList(QtWidgets.QWidget):
filename_item = self.twList.item(row, FileSelectionList.fileColNum)
folder_item = self.twList.item(row, FileSelectionList.folderColNum)
md_item = self.twList.item(row, FileSelectionList.CRFlagColNum)
md_item = self.twList.item(row, FileSelectionList.MDFlagColNum)
type_item = self.twList.item(row, FileSelectionList.typeColNum)
readonly_item = self.twList.item(row, FileSelectionList.readonlyColNum)
@ -340,9 +328,12 @@ class FileSelectionList(QtWidgets.QWidget):
if not ca.is_writable():
readonly_item.setCheckState(QtCore.Qt.CheckState.Checked)
readonly_item.setData(QtCore.Qt.ItemDataRole.UserRole, True)
readonly_item.setText(" ")
else:
readonly_item.setData(QtCore.Qt.ItemDataRole.UserRole, False)
readonly_item.setCheckState(QtCore.Qt.CheckState.Unchecked)
# This is a nbsp it sorts after a space ' '
readonly_item.setText("\xa0")
def get_selected_archive_list(self) -> list[ComicArchive]:
ca_list: list[ComicArchive] = []

View File

@ -7,9 +7,15 @@
<x>0</x>
<y>0</y>
<width>900</width>
<height>413</height>
<height>456</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
@ -20,7 +26,23 @@
<string>Issue Identification Progress</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="1">
<item row="1" column="4">
<widget class="QWidget" name="testCoverContainer" native="true">
<property name="minimumSize">
<size>
<width>110</width>
<height>165</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>110</width>
<height>165</height>
</size>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QWidget" name="archiveCoverContainer" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Expanding">
@ -42,43 +64,42 @@
</property>
</widget>
</item>
<item row="0" column="4">
<widget class="QWidget" name="testCoverContainer" native="true">
<property name="minimumSize">
<size>
<width>110</width>
<height>165</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>110</width>
<height>165</height>
</size>
</property>
</widget>
</item>
<item row="0" column="2">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QProgressBar" name="progressBar">
<property name="value">
<number>0</number>
<item row="1" column="2">
<layout class="QGridLayout" name="gridLayout_2" rowstretch="0,0,0,0,0,0,0" columnstretch="1,0">
<item row="5" column="1">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="invertedAppearance">
<bool>false</bool>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel</set>
</property>
<property name="centerButtons">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label">
<item row="5" column="0">
<widget class="QLabel" name="lblSourceName">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
<string>Metadata source</string>
</property>
</widget>
</item>
<item>
<item row="4" column="0" colspan="2">
<widget class="QTextEdit" name="textEdit">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<family>Courier</family>
@ -89,16 +110,26 @@
</property>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<item row="2" column="0" colspan="2">
<widget class="QProgressBar" name="progressBar">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel</set>
<property name="value">
<number>0</number>
</property>
<property name="centerButtons">
<bool>true</bool>
<property name="invertedAppearance">
<bool>false</bool>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="QLabel" name="label">
<property name="text">
<string/>
</property>
</widget>
</item>

View File

@ -668,7 +668,9 @@ class ComicVineTalker(ComicTalker):
md.story_arcs.append(arc["name"])
for person in issue.get("person_credits", []):
md.add_credit(person["name"], person["role"].title().strip(), False)
roles = utils.split(person.get("role", ""), ",")
for role in roles:
md.add_credit(person["name"], role.title(), False)
md.volume = utils.xlate_int(issue.get("volume"))
if self.use_series_start_as_volume:

View File

@ -46,7 +46,7 @@ install_requires =
pyrate-limiter>=2.6,<3
rapidfuzz>=2.12.0
requests==2.*
settngs==0.9.2
settngs==0.9.3
text2digits
typing-extensions>=4.3.0
wordninja
@ -87,7 +87,8 @@ all =
PyQt5
PyQtWebEngine
comicinfoxml
metron-talker>=0.1.1
gcd-talker>=0.1.0
metron-talker>=0.1.5
pillow-avif-plugin>=1.4.1
py7zr
rarfile>=4.0
@ -96,6 +97,8 @@ avif =
pillow-avif-plugin>=1.4.1
cix =
comicinfoxml
gcd =
gcd-talker>=0.1.0
metron =
metron-talker>=0.1.3

View File

@ -69,7 +69,7 @@ cv_issue_result: dict[str, Any] = {
"id": 57222,
"name": "Esteve Polls",
"site_detail_url": "https://comicvine.gamespot.com/esteve-polls/4040-57222/",
"role": "artist",
"role": "artist, writer",
},
{
"api_detail_url": "https://comicvine.gamespot.com/api/person/4040-48472/",
@ -226,8 +226,12 @@ cv_md = comicapi.genericmetadata.GenericMetadata(
teams=set(),
locations=set(),
credits=[
comicapi.genericmetadata.Credit(person=x["name"], role=x["role"].title(), primary=False)
for x in cv_issue_result["results"]["person_credits"]
comicapi.genericmetadata.Credit(primary=False, person="Dara Naraghi", role="Writer"),
comicapi.genericmetadata.Credit(primary=False, person="Esteve Polls", role="Artist"),
comicapi.genericmetadata.Credit(primary=False, person="Esteve Polls", role="Writer"),
comicapi.genericmetadata.Credit(primary=False, person="Neil Uyetake", role="Letterer"),
comicapi.genericmetadata.Credit(primary=False, person="Sam Kieth", role="Cover"),
comicapi.genericmetadata.Credit(primary=False, person="Ted Adams", role="Editor"),
],
tags=set(),
pages=[],

View File

@ -42,6 +42,7 @@ def test_fetch_issues_in_series(comicvine_api, comic_cache):
def test_fetch_issue_data_by_issue_id(comicvine_api):
result = comicvine_api.fetch_comic_data(140529)
result.notes = None
assert result == testing.comicvine.cv_md

View File

@ -49,6 +49,17 @@ def test_save(
# Read the CBZ
md = tmp_comic.read_metadata("cr")
# This is inserted here because otherwise several other tests
# unrelated to comicvine need to be re-worked
md_saved.credits.insert(
1,
{
"person": "Esteve Polls",
"primary": False,
"role": "Writer",
},
)
# Validate that we got the correct metadata back
assert md == md_saved