1
0
mirror of https://github.com/ciromattia/kcc synced 2026-05-18 21:41:49 +00:00

Merge branch 'master' into metadata-editor-in-bulk

This commit is contained in:
Alex Xu
2026-05-18 08:49:01 -07:00
committed by GitHub
18 changed files with 163 additions and 93 deletions

View File

@@ -24,17 +24,17 @@ jobs:
uses: actions/checkout@v6
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
uses: docker/setup-qemu-action@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@v4
- name: Set Release Date
id: release_date
@@ -43,7 +43,7 @@ jobs:
- name: Docker meta
id: meta
uses: docker/metadata-action@v5
uses: docker/metadata-action@v6
with:
images: ghcr.io/${{ github.repository_owner }}/kcc
# Always creates the "latest" tag
@@ -54,7 +54,7 @@ jobs:
type=raw,value=${{ steps.release_date.outputs.release_date }}
- name: Build and push
uses: docker/build-push-action@v6
uses: docker/build-push-action@v7
with:
platforms: linux/amd64,linux/arm64,linux/arm/v7
context: .

View File

@@ -59,12 +59,12 @@ jobs:
env:
UPDATE_INFO: gh-releases-zsync|ciromattia|kcc|latest|*x86_64.AppImage.zsync
- name: upload artifact
uses: actions/upload-artifact@v6
uses: actions/upload-artifact@v7
with:
name: AppImage
path: './*.AppImage*'
- name: Release
uses: softprops/action-gh-release@v2
uses: softprops/action-gh-release@v3
if: startsWith(github.ref, 'refs/tags/')
with:
prerelease: true

View File

@@ -80,12 +80,12 @@ jobs:
run: |
python setup.py build_binary
- name: upload build
uses: actions/upload-artifact@v6
uses: actions/upload-artifact@v7
with:
name: mac-os-build-${{ runner.arch }}
path: dist/*.dmg
- name: Release
uses: softprops/action-gh-release@v2
uses: softprops/action-gh-release@v3
if: startsWith(github.ref, 'refs/tags/')
with:
prerelease: true

View File

@@ -51,12 +51,12 @@ jobs:
run: |
python3 setup.py build_binary
- name: upload build
uses: actions/upload-artifact@v6
uses: actions/upload-artifact@v7
with:
name: osx-build-${{ runner.arch }}
path: dist/*.dmg
- name: Release
uses: softprops/action-gh-release@v2
uses: softprops/action-gh-release@v3
if: startsWith(github.ref, 'refs/tags/')
with:
prerelease: true

View File

@@ -53,12 +53,12 @@ jobs:
python setup.py ${{ matrix.command }}
- name: upload-unsigned-artifact
id: upload-unsigned-artifact
uses: actions/upload-artifact@v6
uses: actions/upload-artifact@v7
with:
name: windows-build-${{ matrix.entry }}
path: dist/*.exe
- id: optional_step_id
uses: signpath/github-action-submit-signing-request@v2.0
uses: signpath/github-action-submit-signing-request@v2.2
if: ${{ github.repository == 'ciromattia/kcc' }}
with:
api-token: '${{ secrets.SIGNPATH_API_TOKEN }}'
@@ -69,7 +69,7 @@ jobs:
wait-for-completion: true
output-artifact-directory: 'dist/'
- name: Release
uses: softprops/action-gh-release@v2
uses: softprops/action-gh-release@v3
if: startsWith(github.ref, 'refs/tags/')
with:
prerelease: true

View File

@@ -46,12 +46,12 @@ jobs:
python setup.py build_binary
- name: upload-unsigned-artifact
id: upload-unsigned-artifact
uses: actions/upload-artifact@v6
uses: actions/upload-artifact@v7
with:
name: windows7-build
path: dist/*.exe
- id: optional_step_id
uses: signpath/github-action-submit-signing-request@v2.0
uses: signpath/github-action-submit-signing-request@v2.2
if: ${{ github.repository == 'ciromattia/kcc' }}
with:
api-token: '${{ secrets.SIGNPATH_API_TOKEN }}'
@@ -62,7 +62,7 @@ jobs:
wait-for-completion: true
output-artifact-directory: 'dist/'
- name: Release
uses: softprops/action-gh-release@v2
uses: softprops/action-gh-release@v3
if: startsWith(github.ref, 'refs/tags/')
with:
prerelease: true

1
.gitignore vendored
View File

@@ -2,7 +2,6 @@
Pipfile
Pipfile.lock
setup.bat
kindlecomicconverter/sentry.py
other/windows/kindlegen.exe
dist/
build/

View File

@@ -247,7 +247,7 @@ MAIN:
PROCESSING:
-n, --noprocessing Do not modify image and ignore any profile or processing option
--pdfextract Use legacy PDF image extraction method from KCC 8 and earlier.
--legacyextract Use legacy PDF/EPUB image extraction method from earlier KCC versions.
--pdfwidth Render vector PDFs based on device width instead of height.
-u, --upscale Resize images smaller than device's resolution
-s, --stretch Stretch images to device's resolution
@@ -297,6 +297,7 @@ OUTPUT SETTINGS:
-b BATCHSPLIT, --batchsplit BATCHSPLIT
Split output into multiple files. 0: Don't split 1: Automatic mode 2: Consider every subdirectory as separate volume [Default=0]
--spreadshift Shift first page to opposite side in landscape for two page spread alignment
--onepagelandscape Show a single centered page in landscape
--norotate Do not rotate double page spreads in spread splitter option.
--rotateright Rotate double page spreads in opposite direction.
--rotatefirst Put rotated spread first in spread splitter option.
@@ -442,7 +443,6 @@ Older links (dead):
## PRIVACY
**KCC** is initiating internet connections in two cases:
* During startup - Version check and announcement check.
* When error occurs - Automatic reporting on Windows and macOS.
## KNOWN ISSUES
Please check [wiki page](https://github.com/ciromattia/kcc/wiki/Known-issues).

View File

@@ -750,14 +750,12 @@ Higher values are larger and higher quality, and may resolve blank page issues.<
</widget>
</item>
<item row="9" column="0">
<widget class="QCheckBox" name="pdfExtractBox">
<widget class="QCheckBox" name="legacyExtractBox">
<property name="toolTip">
<string>Use the PDF image extraction method from KCC 8 and earlier.
Useful for really weird PDFs.</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Use the PDF/EPUB image extraction method from older KCC versions.&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;Use if standard extraction fails for whatever reason.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>PDF Legacy Extract</string>
<string>Legacy Extract</string>
</property>
</widget>
</item>
@@ -885,7 +883,7 @@ Ignored for Kindle EPUB/MOBI and all PDF.</string>
</property>
</widget>
</item>
<item row="12" column="1">
<item row="12" column="2">
<widget class="QCheckBox" name="tempDirBox">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Unchecked - Main Drive&lt;br/&gt;&lt;/span&gt;Use dedicated temporary directory on main OS drive.&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Checked - Source File Drive&lt;br/&gt;&lt;/span&gt;Create temporary file directory on source file drive.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
@@ -895,6 +893,16 @@ Ignored for Kindle EPUB/MOBI and all PDF.</string>
</property>
</widget>
</item>
<item row="12" column="1">
<widget class="QCheckBox" name="onePageLandscapeBox">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Unchecked - 2 page landscape&lt;br/&gt;&lt;/span&gt;2 viewports for left and right pages&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Checked - 1 page landscape&lt;br/&gt;&lt;/span&gt;A single centered viewport for 1 page&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>1 Page Landscape</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>

View File

@@ -38,7 +38,6 @@ from xml.sax.saxutils import escape
from psutil import Process
from copy import copy
from packaging.version import Version
from raven import Client
from tempfile import gettempdir
from .shared import HTMLStripper, sanitizeTrace, walkLevel, subprocess_run
@@ -327,8 +326,8 @@ class WorkerThread(QThread):
options.maximizestrips = True
if GUI.disableProcessingBox.isChecked():
options.noprocessing = True
if GUI.pdfExtractBox.isChecked():
options.pdfextract = True
if GUI.legacyExtractBox.isChecked():
options.legacyextract = True
if GUI.pdfWidthBox.isChecked():
options.pdfwidth = True
if GUI.smartCoverCropBox.isChecked():
@@ -345,6 +344,8 @@ class WorkerThread(QThread):
options.tempdir = True
if GUI.spreadShiftBox.isChecked():
options.spreadshift = True
if GUI.onePageLandscapeBox.isChecked():
options.onepagelandscape = True
if GUI.fileFusionBox.isChecked():
options.filefusion = True
else:
@@ -445,8 +446,6 @@ class WorkerThread(QThread):
_, _, traceback = sys.exc_info()
MW.showDialog.emit("Error during conversion %s:\n\n%s\n\nTraceback:\n%s"
% (jobargv[-1], str(err), sanitizeTrace(traceback)), 'error')
if ' is corrupted.' not in str(err):
GUI.sentry.captureException()
MW.addMessage.emit('Error during conversion! Please consult '
'<a href="https://github.com/ciromattia/kcc/wiki/Error-messages">wiki</a> '
'for more details.', 'error', False)
@@ -564,6 +563,7 @@ class WorkerThread(QThread):
os.remove(path)
elif os.path.isdir(path):
rmtree(path, True)
comic2ebook.checkPre('LLL-')
GUI.progress.content = ''
GUI.progress.stop()
MW.hideProgressBar.emit()
@@ -627,7 +627,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
GUI.jobList.clear()
if self.tar or self.sevenzip:
fnames = QFileDialog.getOpenFileNames(MW, 'Select file', self.lastPath,
'Comic (*.cbz *.cbr *.cb7 *.zip *.rar *.7z *.pdf);;All (*.*)')
'Comic (*.cbz *.cbr *.cb7 *.zip *.rar *.7z *.epub *.pdf);;All (*.*)')
else:
fnames = QFileDialog.getOpenFileNames(MW, 'Select file', self.lastPath,
'Comic (*.pdf);;All (*.*)')
@@ -699,7 +699,6 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
self.editor.loadData(files)
except Exception as err:
_, _, traceback = sys.exc_info()
GUI.sentry.captureException()
self.showDialog("Failed to parse metadata!\n\n%s\n\nTraceback:\n%s"
% (str(err), sanitizeTrace(traceback)), 'error')
else:
@@ -1101,7 +1100,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
'colorBox': GUI.colorBox.checkState(),
'eraseRainbowBox': GUI.eraseRainbowBox.checkState(),
'disableProcessingBox': GUI.disableProcessingBox.checkState(),
'pdfExtractBox': GUI.pdfExtractBox.checkState(),
'legacyExtractBox': GUI.legacyExtractBox.checkState(),
'pdfWidthBox': GUI.pdfWidthBox.checkState(),
'smartCoverCropBox': GUI.smartCoverCropBox.checkState(),
'coverFillBox': GUI.coverFillBox.checkState(),
@@ -1118,6 +1117,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
'deleteBox': GUI.deleteBox.checkState(),
'tempDirBox': GUI.tempDirBox.checkState(),
'spreadShiftBox': GUI.spreadShiftBox.checkState(),
'onePageLandscapeBox': GUI.onePageLandscapeBox.checkState(),
'fileFusionBox': GUI.fileFusionBox.checkState(),
'defaultOutputFolderBox': GUI.defaultOutputFolderBox.checkState(),
'noRotateBox': GUI.noRotateBox.checkState(),
@@ -1141,7 +1141,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
GUI.jobList.clear()
formats = ['.pdf']
if self.tar or self.sevenzip:
formats.extend(['.cb7', '.7z', '.cbz', '.zip', '.cbr', '.rar'])
formats.extend(['.cb7', '.7z', '.cbz', '.zip', '.cbr', '.rar', '.epub'])
if os.path.isdir(message):
GUI.jobList.addItem(message)
GUI.jobList.scrollToBottom()
@@ -1228,7 +1228,6 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
self.croppingPowerValue = 1.0
self.currentMode = 1
self.targetDirectory = ''
self.sentry = Client(release=__version__)
if sys.platform.startswith('win'):
# noinspection PyUnresolvedReferences
from psutil import BELOW_NORMAL_PRIORITY_CLASS
@@ -1775,7 +1774,6 @@ class KCCGUI_MetaEditor(KCC_ui_editor.Ui_editorDialog):
self.parser.saveXML()
except Exception as err:
_, _, traceback = sys.exc_info()
GUI.sentry.captureException()
GUI.showDialog("Failed to save metadata!\n\n%s\n\nTraceback:\n%s"
% (str(err), sanitizeTrace(traceback)), 'error')
self.ui.close()

View File

@@ -389,10 +389,10 @@ class Ui_mainWindow(object):
self.gridLayout_2.addWidget(self.qualityBox, 1, 2, 1, 1)
self.pdfExtractBox = QCheckBox(self.optionWidget)
self.pdfExtractBox.setObjectName(u"pdfExtractBox")
self.legacyExtractBox = QCheckBox(self.optionWidget)
self.legacyExtractBox.setObjectName(u"legacyExtractBox")
self.gridLayout_2.addWidget(self.pdfExtractBox, 9, 0, 1, 1)
self.gridLayout_2.addWidget(self.legacyExtractBox, 9, 0, 1, 1)
self.colorBox = QCheckBox(self.optionWidget)
self.colorBox.setObjectName(u"colorBox")
@@ -453,7 +453,12 @@ class Ui_mainWindow(object):
self.tempDirBox = QCheckBox(self.optionWidget)
self.tempDirBox.setObjectName(u"tempDirBox")
self.gridLayout_2.addWidget(self.tempDirBox, 12, 1, 1, 1)
self.gridLayout_2.addWidget(self.tempDirBox, 12, 2, 1, 1)
self.onePageLandscapeBox = QCheckBox(self.optionWidget)
self.onePageLandscapeBox.setObjectName(u"onePageLandscapeBox")
self.gridLayout_2.addWidget(self.onePageLandscapeBox, 12, 1, 1, 1)
self.gridLayout.addWidget(self.optionWidget, 5, 0, 1, 2)
@@ -785,11 +790,9 @@ class Ui_mainWindow(object):
#endif // QT_CONFIG(tooltip)
self.qualityBox.setText(QCoreApplication.translate("mainWindow", u"Panel View 4/2/HQ", None))
#if QT_CONFIG(tooltip)
self.pdfExtractBox.setToolTip(QCoreApplication.translate("mainWindow", u"Use the PDF image extraction method from KCC 8 and earlier.\n"
"\n"
"Useful for really weird PDFs.", None))
self.legacyExtractBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p>Use the PDF/EPUB image extraction method from older KCC versions.</p><p><br/></p><p>Use if standard extraction fails for whatever reason.</p></body></html>", None))
#endif // QT_CONFIG(tooltip)
self.pdfExtractBox.setText(QCoreApplication.translate("mainWindow", u"PDF Legacy Extract", None))
self.legacyExtractBox.setText(QCoreApplication.translate("mainWindow", u"Legacy Extract", None))
#if QT_CONFIG(tooltip)
self.colorBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p style='white-space:pre'>Disable conversion to grayscale.</p></body></html>", None))
#endif // QT_CONFIG(tooltip)
@@ -830,6 +833,10 @@ class Ui_mainWindow(object):
self.tempDirBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Main Drive<br/></span>Use dedicated temporary directory on main OS drive.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Source File Drive<br/></span>Create temporary file directory on source file drive.</p></body></html>", None))
#endif // QT_CONFIG(tooltip)
self.tempDirBox.setText(QCoreApplication.translate("mainWindow", u"Temp Directory", None))
#if QT_CONFIG(tooltip)
self.onePageLandscapeBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - 2 page landscape<br/></span>2 viewports for left and right pages</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - 1 page landscape<br/></span>A single centered viewport for 1 page</p></body></html>", None))
#endif // QT_CONFIG(tooltip)
self.onePageLandscapeBox.setText(QCoreApplication.translate("mainWindow", u"1 Page Landscape", None))
#if QT_CONFIG(tooltip)
self.convertButton.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p style='white-space:pre'>Shift+Click to select the output directory for this list.</p></body></html>", None))
#endif // QT_CONFIG(tooltip)

View File

@@ -22,7 +22,9 @@ from collections import Counter
import os
import pathlib
import re
import shutil
import sys
import xml.etree.ElementTree as ET
from argparse import ArgumentParser
from time import perf_counter, strftime, gmtime
from copy import copy
@@ -30,8 +32,8 @@ from glob import glob, escape
from re import sub
from stat import S_IWRITE, S_IREAD, S_IEXEC
from typing import List
from zipfile import ZipFile, ZIP_STORED, ZIP_DEFLATED
from tempfile import mkdtemp, gettempdir, TemporaryFile
from zipfile import ZipFile, ZIP_STORED
from tempfile import mkdtemp, gettempdir
from shutil import move, copytree, rmtree, copyfile
from multiprocessing import Pool, cpu_count
from uuid import uuid4
@@ -90,6 +92,7 @@ def main(argv=None):
os.remove(path)
elif os.path.isdir(path):
rmtree(path, True)
checkPre('LLL-')
return 0
@@ -466,6 +469,8 @@ def buildOPF(dstdir, title, filelist, originalpath, cover=None):
pageside = "right"
for entry, prop in zip(reflist, page_spread_property_list):
if options.onepagelandscape:
prop = 'center'
f.write(f'<itemref idref="page_{entry}" {pageSpreadProperty(prop)}/>\n')
f.write("</spine>\n</package>\n")
@@ -892,9 +897,12 @@ def getWorkFolder(afile, workdir=None):
fullPath = os.path.join(workdir, 'OEBPS', 'Images')
else:
fullPath = workdir
check_path = gettempdir()
if options.tempdir:
check_path = os.path.dirname(afile)
else:
check_path = gettempdir()
if os.path.isdir(afile):
if disk_usage(check_path)[2] < getDirectorySize(afile) * 2.5:
raise UserWarning("Not enough disk space to perform conversion.")
@@ -913,7 +921,7 @@ def getWorkFolder(afile, workdir=None):
os.makedirs(fullPath)
path = workdir
sanitizePermissions(path)
if options.pdfextract:
if options.legacyextract:
pdf = pdfjpgextract.PdfJpgExtract(afile, fullPath)
njpg = pdf.extract()
if njpg == 0:
@@ -952,11 +960,68 @@ def getWorkFolder(afile, workdir=None):
for file in os.listdir(os.path.join(fullPath, tdir[0])):
move(os.path.join(fullPath, tdir[0], file), fullPath)
os.rmdir(os.path.join(fullPath, tdir[0]))
if options.legacyextract:
return workdir
if afile.lower().endswith('.epub'):
container = ET.parse(os.path.join(path, 'META-INF', 'container.xml'))
opf_path = container.find(r'.//{*}rootfile').attrib['full-path']
opf_path = os.path.join(path, opf_path)
opf = ET.parse(opf_path)
spine = []
for spine_item in opf.findall(r'.//{*}itemref'):
spine.append(spine_item.attrib.get('idref'))
manifest_dict = {}
for manifest_item in opf.findall(".//*[@media-type='application/xhtml+xml']"):
manifest_dict[manifest_item.attrib.get('id')] = manifest_item.attrib.get('href')
ordered_image_paths = []
for i, spine_item in enumerate(spine):
if spine_item not in manifest_dict:
continue
page_path = os.path.join(os.path.dirname(opf_path), manifest_dict[spine_item])
page = ET.parse(page_path)
imgs = page.findall(r'.//{*}img') + page.findall(r'.//{*}image')
largest_size = 0
img_path = None
for img in imgs:
for key in img.attrib:
if 'src' in key or 'href' in key:
temp_img_path = img.attrib[key]
if temp_img_path.startswith('..'):
temp_img_path = os.path.join(os.path.dirname(opf_path), os.path.dirname(manifest_dict[spine_item]), temp_img_path)
else:
temp_img_path = os.path.join(os.path.dirname(opf_path), os.path.dirname(manifest_dict[spine_item]), temp_img_path)
try:
temp_size = os.path.getsize(temp_img_path)
if temp_size > largest_size:
largest_size = temp_size
img_path = temp_img_path
except OSError:
pass
# TODO empty image
if img_path:
ordered_image_paths.append(img_path)
# fallback if naive spine extraction fails
if not ordered_image_paths:
return workdir
if options.tempdir:
workdir2 = mkdtemp('', 'KCC-', os.path.dirname(afile))
else:
workdir2 = mkdtemp('', 'KCC-')
for i, img_path in enumerate(ordered_image_paths):
_, ext = os.path.splitext(img_path)
fullpath2 = os.path.join(workdir2, 'OEBPS', 'Images')
os.makedirs(fullpath2, exist_ok=True)
shutil.copyfile(img_path, os.path.join(fullpath2, f"{i}{ext}"))
rmtree(workdir, True)
return workdir2
return workdir
except OSError as e:
rmtree(workdir, True)
raise UserWarning(e)
finally:
pass
else:
raise UserWarning("Failed to open source file/directory.")
@@ -1393,6 +1458,8 @@ def makeParser():
"2: Consider every subdirectory as separate volume [Default=0]")
output_options.add_argument("--spreadshift", action="store_true", dest="spreadshift", default=False,
help="Shift first page to opposite side in landscape for spread alignment")
output_options.add_argument("--onepagelandscape", action="store_true", dest="onepagelandscape", default=False,
help="Show a single centered page in landscape")
output_options.add_argument("--norotate", action="store_true", dest="norotate", default=False,
help="Do not rotate double page spreads in spread splitter option.")
output_options.add_argument("--rotateright", action="store_true", dest="rotateright", default=False,
@@ -1402,8 +1469,8 @@ def makeParser():
processing_options.add_argument("-n", "--noprocessing", action="store_true", dest="noprocessing", default=False,
help="Do not modify image and ignore any profile or processing option")
processing_options.add_argument("--pdfextract", action="store_true", dest="pdfextract", default=False,
help="Use the legacy PDF image extraction method from KCC 8 and earlier")
processing_options.add_argument("--legacyextract", action="store_true", dest="legacyextract", default=False,
help="Use the legacy PDF/EPUB image extraction method from older KCC versions")
processing_options.add_argument("--pdfwidth", action="store_true", dest="pdfwidth", default=False,
help="Render vector PDFs to device width instead of height.")
processing_options.add_argument("--smartcovercrop", action="store_true", dest="smartcovercrop", default=False,
@@ -1609,33 +1676,30 @@ def checkTools(source):
sys.exit(1)
def checkPre(source):
def checkPre(source='KCC-'):
# Make sure that all temporary files are gone
for root, dirs, _ in walkLevel(gettempdir(), 0):
for tempdir in dirs:
if tempdir.startswith('KCC-'):
if tempdir.startswith(source):
rmtree(os.path.join(root, tempdir), True)
# Make sure that target directory is writable
if os.path.isdir(source):
src = os.path.abspath(os.path.join(source, '..'))
else:
src = os.path.dirname(source)
try:
with TemporaryFile(prefix='KCC-', dir=src):
pass
except Exception:
raise UserWarning("Target directory is not writable.")
def makeFusion(sources: List[str]):
if len(sources) < 2:
raise UserWarning('Fusion requires at least 2 sources. Did you forget to uncheck fusion?')
start = perf_counter()
first_path = Path(sources[0])
if first_path.is_file():
fusion_path = first_path.parent.joinpath(first_path.stem + ' [fused]')
if options.tempdir:
fusion_parent = first_path.parent
else:
fusion_path = first_path.parent.joinpath(first_path.name + ' [fused]')
# LLL is after KCC
checkPre('LLL-')
fusion_parent = Path(mkdtemp('', 'LLL-'))
if first_path.is_file():
fusion_path = fusion_parent.joinpath(first_path.stem + ' [fused]')
else:
fusion_path = fusion_parent.joinpath(first_path.name + ' [fused]')
print("Running Fusion")
# Check if prefix is needed when user-specified ordering differs from OS natural sorting
@@ -1644,7 +1708,6 @@ def makeFusion(sources: List[str]):
for index, source in enumerate(sources, start=1):
print(f"Processing {source}...")
checkPre(source)
print("Checking images...")
source_path = Path(source)
# Add the fusion_0001_ prefix to maintain user-specified order if needed
@@ -1676,7 +1739,9 @@ def makeBook(source, qtgui=None, job_progress=''):
GUI.progressBarTick.emit('1')
else:
checkTools(source)
checkPre(source)
checkPre()
if not options.filefusion:
checkPre('LLL-')
print(f"{job_progress}Preparing source images...")
path = getWorkFolder(source)
print(f"{job_progress}Checking images...")

View File

@@ -122,10 +122,6 @@ def dependencyCheck(level):
missing.append('PySide 6.0.0')
except ImportError:
missing.append('PySide 6.0.0+')
try:
import raven
except ImportError:
missing.append('raven 6.0.0+')
if level > 1:
try:
from psutil import __version__ as psutilVersion

View File

@@ -1,8 +1,8 @@
Pillow>=11.3.0
psutil>=5.9.5
requests>=2.31.0
python-slugify>=1.2.1
packaging>=23.2
requests>=2.34.2
python-slugify>=8.0.4
packaging>=26.2
mozjpeg-lossless-optimization>=1.2.0
natsort>=8.4.0
distro>=1.8.0

View File

@@ -1,10 +1,9 @@
PySide6==6.4.3
Pillow>=11.3.0
psutil>=5.9.5
requests>=2.31.0
python-slugify>=1.2.1
raven>=6.0.0
packaging>=23.2
requests>=2.34.2
python-slugify>=8.0.4
packaging>=26.2
mozjpeg-lossless-optimization>=1.2.0
natsort>=8.4.0
distro>=1.8.0

View File

@@ -1,10 +1,9 @@
PySide6==6.1.3
Pillow>=9
psutil>=5.9.5
requests>=2.31.0
python-slugify>=1.2.1
raven>=6.0.0
packaging>=23.2
requests>=2.34.2
python-slugify>=8.0.4
packaging>=26.2
mozjpeg-lossless-optimization>=1.2.0
natsort>=8.4.0
distro>=1.8.0

View File

@@ -1,10 +1,9 @@
PySide6<6.10
Pillow>=11.3.0
psutil>=5.9.5
requests>=2.31.0
python-slugify>=1.2.1,<9.0.0
raven>=6.0.0
packaging>=23.2
requests>=2.34.2
python-slugify>=8.0.4,<9.0.0
packaging>=26.2
mozjpeg-lossless-optimization>=1.2.0
natsort>=8.4.0
distro>=1.8.0

View File

@@ -153,11 +153,11 @@ setuptools.setup(
'psutil>=5.9.5',
'requests>=2.31.0',
'python-slugify>=1.2.1,<9.0.0',
'raven>=6.0.0',
'mozjpeg-lossless-optimization>=1.2.0',
'natsort>=8.4.0',
'distro>=1.8.0',
'numpy>=1.22.4',
'packaging>=23.2',
'PyMuPDF>=1.16.1',
],
classifiers=[],