mirror of
https://github.com/ciromattia/kcc
synced 2025-12-13 09:46:25 +00:00
Added ability to combine multiple CBZ into one files (#960)
* Added basic CBZ combine func Need to add support for epub and maybe mobi. * Removed irrelevant code for CBZ file fusion * Fixed false description * Removed irrelevant code * Removed redundant code Replaced page tracker and os.rename with os.renames. Removed unneeded reference to gui. Changed mkdir to mkdtemp. * Made folder and cbz work together You can select multiple folders of images, multiple cbz files, and folders with subfolders. Fusion will combine them all together at the same time. Mainly added this to idiot proof it. * Updated gui Removed redundant tooltip * simplify code * fix merging chapter folders with . * uncheck fusion message --------- Co-authored-by: Alex Xu <alexkurosakimh3@gmail.com>
This commit is contained in:
10
gui/KCC.ui
10
gui/KCC.ui
@@ -590,6 +590,16 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="6" column="0">
|
||||||
|
<widget class="QCheckBox" name="fileFusionBox">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><html><head/><body><p>Combines all selected files into a single file. (Helpful for combining chapters into volumes.)</p></body></html></string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>File Fusion</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item row="2" column="1">
|
<item row="2" column="1">
|
||||||
<widget class="QCheckBox" name="upscaleBox">
|
<widget class="QCheckBox" name="upscaleBox">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
|
|||||||
@@ -267,6 +267,10 @@ class WorkerThread(QThread):
|
|||||||
options.delete = True
|
options.delete = True
|
||||||
if GUI.spreadShiftBox.isChecked():
|
if GUI.spreadShiftBox.isChecked():
|
||||||
options.spreadshift = True
|
options.spreadshift = True
|
||||||
|
if GUI.fileFusionBox.isChecked():
|
||||||
|
options.filefusion = True
|
||||||
|
else:
|
||||||
|
options.filefusion = False
|
||||||
if GUI.noRotateBox.isChecked():
|
if GUI.noRotateBox.isChecked():
|
||||||
options.norotate = True
|
options.norotate = True
|
||||||
if GUI.mozJpegBox.checkState() == Qt.CheckState.PartiallyChecked:
|
if GUI.mozJpegBox.checkState() == Qt.CheckState.PartiallyChecked:
|
||||||
@@ -288,6 +292,19 @@ class WorkerThread(QThread):
|
|||||||
if GUI.jobList.item(i).icon().isNull():
|
if GUI.jobList.item(i).icon().isNull():
|
||||||
currentJobs.append(str(GUI.jobList.item(i).text()))
|
currentJobs.append(str(GUI.jobList.item(i).text()))
|
||||||
GUI.jobList.clear()
|
GUI.jobList.clear()
|
||||||
|
if options.filefusion:
|
||||||
|
bookDir = []
|
||||||
|
MW.addMessage.emit('Attempting file fusion', 'info', False)
|
||||||
|
for job in currentJobs:
|
||||||
|
bookDir.append(job)
|
||||||
|
try:
|
||||||
|
comic2ebook.options = comic2ebook.checkOptions(copy(options))
|
||||||
|
currentJobs.clear()
|
||||||
|
currentJobs.append(comic2ebook.makeFusion(bookDir))
|
||||||
|
MW.addMessage.emit('Created fusion at ' + currentJobs[0], 'info', False)
|
||||||
|
except Exception as e:
|
||||||
|
print('Fusion Failed. ' + str(e))
|
||||||
|
MW.addMessage.emit('Fusion Failed. ' + str(e), 'error', True)
|
||||||
for job in currentJobs:
|
for job in currentJobs:
|
||||||
sleep(0.5)
|
sleep(0.5)
|
||||||
if not self.conversionAlive:
|
if not self.conversionAlive:
|
||||||
@@ -433,6 +450,12 @@ class WorkerThread(QThread):
|
|||||||
move(item, GUI.targetDirectory)
|
move(item, GUI.targetDirectory)
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
if options.filefusion:
|
||||||
|
for path in currentJobs:
|
||||||
|
if os.path.isfile(path):
|
||||||
|
os.remove(path)
|
||||||
|
elif os.path.isdir(path):
|
||||||
|
rmtree(path)
|
||||||
GUI.progress.content = ''
|
GUI.progress.content = ''
|
||||||
GUI.progress.stop()
|
GUI.progress.stop()
|
||||||
MW.hideProgressBar.emit()
|
MW.hideProgressBar.emit()
|
||||||
@@ -825,6 +848,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
'heightBox': GUI.heightBox.value(),
|
'heightBox': GUI.heightBox.value(),
|
||||||
'deleteBox': GUI.deleteBox.checkState().value,
|
'deleteBox': GUI.deleteBox.checkState().value,
|
||||||
'spreadShiftBox': GUI.spreadShiftBox.checkState().value,
|
'spreadShiftBox': GUI.spreadShiftBox.checkState().value,
|
||||||
|
'fileFusionBox': GUI.fileFusionBox.checkState().value,
|
||||||
'noRotateBox': GUI.noRotateBox.checkState().value,
|
'noRotateBox': GUI.noRotateBox.checkState().value,
|
||||||
'maximizeStrips': GUI.maximizeStrips.checkState().value,
|
'maximizeStrips': GUI.maximizeStrips.checkState().value,
|
||||||
'gammaSlider': float(self.gammaValue) * 100,
|
'gammaSlider': float(self.gammaValue) * 100,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Resource object code (Python 3)
|
# Resource object code (Python 3)
|
||||||
# Created by: object code
|
# Created by: object code
|
||||||
# Created by: The Resource Compiler for Qt version 6.9.0
|
# Created by: The Resource Compiler for Qt version 6.9.1
|
||||||
# WARNING! All changes made in this file will be lost!
|
# WARNING! All changes made in this file will be lost!
|
||||||
|
|
||||||
from PySide6 import QtCore
|
from PySide6 import QtCore
|
||||||
@@ -11612,51 +11612,51 @@ qt_resource_struct = b"\
|
|||||||
\x00\x00\x00X\x00\x02\x00\x00\x00\x04\x00\x00\x00\x07\
|
\x00\x00\x00X\x00\x02\x00\x00\x00\x04\x00\x00\x00\x07\
|
||||||
\x00\x00\x00\x00\x00\x00\x00\x00\
|
\x00\x00\x00\x00\x00\x00\x00\x00\
|
||||||
\x00\x00\x01\xc0\x00\x00\x00\x00\x00\x01\x00\x02.\xed\
|
\x00\x00\x01\xc0\x00\x00\x00\x00\x00\x01\x00\x02.\xed\
|
||||||
\x00\x00\x01\x97 [\xc3\x1b\
|
\x00\x00\x01\x97\x5c>\xea\xe6\
|
||||||
\x00\x00\x01\xfe\x00\x00\x00\x00\x00\x01\x00\x02\x83\x87\
|
\x00\x00\x01\xfe\x00\x00\x00\x00\x00\x01\x00\x02\x83\x87\
|
||||||
\x00\x00\x01\x97 [\xc3\x19\
|
\x00\x00\x01\x97\x5c>\xea\xe5\
|
||||||
\x00\x00\x01\xea\x00\x00\x00\x00\x00\x01\x00\x02Y\x8c\
|
\x00\x00\x01\xea\x00\x00\x00\x00\x00\x01\x00\x02Y\x8c\
|
||||||
\x00\x00\x01\x97 [\xc3\x19\
|
\x00\x00\x01\x97\x5c>\xea\xe4\
|
||||||
\x00\x00\x01\xd6\x00\x00\x00\x00\x00\x01\x00\x02N)\
|
\x00\x00\x01\xd6\x00\x00\x00\x00\x00\x01\x00\x02N)\
|
||||||
\x00\x00\x01\x97 [\xc3\x1a\
|
\x00\x00\x01\x97\x5c>\xea\xe5\
|
||||||
\x00\x00\x00X\x00\x02\x00\x00\x00\x04\x00\x00\x00\x0c\
|
\x00\x00\x00X\x00\x02\x00\x00\x00\x04\x00\x00\x00\x0c\
|
||||||
\x00\x00\x00\x00\x00\x00\x00\x00\
|
\x00\x00\x00\x00\x00\x00\x00\x00\
|
||||||
\x00\x00\x00\xa6\x00\x00\x00\x00\x00\x01\x00\x01(\x97\
|
\x00\x00\x00\xa6\x00\x00\x00\x00\x00\x01\x00\x01(\x97\
|
||||||
\x00\x00\x01\x97 [\xc3\x1b\
|
\x00\x00\x01\x97\x5c>\xea\xe6\
|
||||||
\x00\x00\x00\xbc\x00\x00\x00\x00\x00\x01\x00\x011\xef\
|
\x00\x00\x00\xbc\x00\x00\x00\x00\x00\x01\x00\x011\xef\
|
||||||
\x00\x00\x01\x97 [\xc3\x1c\
|
\x00\x00\x01\x97\x5c>\xea\xe7\
|
||||||
\x00\x00\x00\x8c\x00\x00\x00\x00\x00\x01\x00\x01\x1d\x90\
|
\x00\x00\x00\x8c\x00\x00\x00\x00\x00\x01\x00\x01\x1d\x90\
|
||||||
\x00\x00\x01\x97 [\xc3\x1a\
|
\x00\x00\x01\x97\x5c>\xea\xe5\
|
||||||
\x00\x00\x00\xd0\x00\x00\x00\x00\x00\x01\x00\x01:\x05\
|
\x00\x00\x00\xd0\x00\x00\x00\x00\x00\x01\x00\x01:\x05\
|
||||||
\x00\x00\x01\x97 [\xc3\x1c\
|
\x00\x00\x01\x97\x5c>\xea\xe6\
|
||||||
\x00\x00\x00X\x00\x02\x00\x00\x00\x03\x00\x00\x00\x11\
|
\x00\x00\x00X\x00\x02\x00\x00\x00\x03\x00\x00\x00\x11\
|
||||||
\x00\x00\x00\x00\x00\x00\x00\x00\
|
\x00\x00\x00\x00\x00\x00\x00\x00\
|
||||||
\x00\x00\x02B\x00\x00\x00\x00\x00\x01\x00\x02\xb5\xd3\
|
\x00\x00\x02B\x00\x00\x00\x00\x00\x01\x00\x02\xb5\xd3\
|
||||||
\x00\x00\x01\x97 [\xc3*\
|
\x00\x00\x01\x97\x5c>\xea\xf1\
|
||||||
\x00\x00\x02\x14\x00\x00\x00\x00\x00\x01\x00\x02\x9f\xd6\
|
\x00\x00\x02\x14\x00\x00\x00\x00\x00\x01\x00\x02\x9f\xd6\
|
||||||
\x00\x00\x01\x97 [\xc3(\
|
\x00\x00\x01\x97\x5c>\xea\xf0\
|
||||||
\x00\x00\x02*\x00\x00\x00\x00\x00\x01\x00\x02\xa93\
|
\x00\x00\x02*\x00\x00\x00\x00\x00\x01\x00\x02\xa93\
|
||||||
\x00\x00\x01\x97 [\xc3(\
|
\x00\x00\x01\x97\x5c>\xea\xef\
|
||||||
\x00\x00\x00X\x00\x02\x00\x00\x00\x07\x00\x00\x00\x15\
|
\x00\x00\x00X\x00\x02\x00\x00\x00\x07\x00\x00\x00\x15\
|
||||||
\x00\x00\x00\x00\x00\x00\x00\x00\
|
\x00\x00\x00\x00\x00\x00\x00\x00\
|
||||||
\x00\x00\x01\x1c\x00\x00\x00\x00\x00\x01\x00\x01P\xb1\
|
\x00\x00\x01\x1c\x00\x00\x00\x00\x00\x01\x00\x01P\xb1\
|
||||||
\x00\x00\x01\x97 [\xc3+\
|
\x00\x00\x01\x97\x5c>\xea\xf1\
|
||||||
\x00\x00\x012\x00\x00\x00\x00\x00\x01\x00\x01yY\
|
\x00\x00\x012\x00\x00\x00\x00\x00\x01\x00\x01yY\
|
||||||
\x00\x00\x01\x97 [\xc3(\
|
\x00\x00\x01\x97\x5c>\xea\xef\
|
||||||
\x00\x00\x01\x94\x00\x00\x00\x00\x00\x01\x00\x01\xd2-\
|
\x00\x00\x01\x94\x00\x00\x00\x00\x00\x01\x00\x01\xd2-\
|
||||||
\x00\x00\x01\x97 [\xc3)\
|
\x00\x00\x01\x97\x5c>\xea\xf0\
|
||||||
\x00\x00\x01z\x00\x00\x00\x00\x00\x01\x00\x01\x8c\xe6\
|
\x00\x00\x01z\x00\x00\x00\x00\x00\x01\x00\x01\x8c\xe6\
|
||||||
\x00\x00\x01\x97 [\xc3'\
|
\x00\x00\x01\x97\x5c>\xea\xef\
|
||||||
\x00\x00\x01\x04\x00\x00\x00\x00\x00\x01\x00\x01LR\
|
\x00\x00\x01\x04\x00\x00\x00\x00\x00\x01\x00\x01LR\
|
||||||
\x00\x00\x01\x97 [\xc3!\
|
\x00\x00\x01\x97\x5c>\xea\xea\
|
||||||
\x00\x00\x00\xe8\x00\x00\x00\x00\x00\x01\x00\x01?\xe9\
|
\x00\x00\x00\xe8\x00\x00\x00\x00\x00\x01\x00\x01?\xe9\
|
||||||
\x00\x00\x01\x97 [\xc3&\
|
\x00\x00\x01\x97\x5c>\xea\xee\
|
||||||
\x00\x00\x01T\x00\x00\x00\x00\x00\x01\x00\x01\x82\xb0\
|
\x00\x00\x01T\x00\x00\x00\x00\x00\x01\x00\x01\x82\xb0\
|
||||||
\x00\x00\x01\x97 [\xc3'\
|
\x00\x00\x01\x97\x5c>\xea\xef\
|
||||||
\x00\x00\x00X\x00\x02\x00\x00\x00\x01\x00\x00\x00\x1d\
|
\x00\x00\x00X\x00\x02\x00\x00\x00\x01\x00\x00\x00\x1d\
|
||||||
\x00\x00\x00\x00\x00\x00\x00\x00\
|
\x00\x00\x00\x00\x00\x00\x00\x00\
|
||||||
\x00\x00\x00h\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
|
\x00\x00\x00h\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
|
||||||
\x00\x00\x01\x97 [\xc3&\
|
\x00\x00\x01\x97\x5c>\xea\xee\
|
||||||
"
|
"
|
||||||
|
|
||||||
def qInitResources():
|
def qInitResources():
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
################################################################################
|
################################################################################
|
||||||
## Form generated from reading UI file 'KCC.ui'
|
## Form generated from reading UI file 'KCC.ui'
|
||||||
##
|
##
|
||||||
## Created by: Qt User Interface Compiler version 6.9.0
|
## Created by: Qt User Interface Compiler version 6.9.1
|
||||||
##
|
##
|
||||||
## WARNING! All changes made in this file will be lost when recompiling UI file!
|
## WARNING! All changes made in this file will be lost when recompiling UI file!
|
||||||
################################################################################
|
################################################################################
|
||||||
@@ -320,6 +320,11 @@ class Ui_mainWindow(object):
|
|||||||
|
|
||||||
self.gridLayout_2.addWidget(self.spreadShiftBox, 5, 0, 1, 1)
|
self.gridLayout_2.addWidget(self.spreadShiftBox, 5, 0, 1, 1)
|
||||||
|
|
||||||
|
self.fileFusionBox = QCheckBox(self.optionWidget)
|
||||||
|
self.fileFusionBox.setObjectName(u"fileFusionBox")
|
||||||
|
|
||||||
|
self.gridLayout_2.addWidget(self.fileFusionBox, 6, 0, 1, 1)
|
||||||
|
|
||||||
self.upscaleBox = QCheckBox(self.optionWidget)
|
self.upscaleBox = QCheckBox(self.optionWidget)
|
||||||
self.upscaleBox.setObjectName(u"upscaleBox")
|
self.upscaleBox.setObjectName(u"upscaleBox")
|
||||||
self.upscaleBox.setTristate(True)
|
self.upscaleBox.setTristate(True)
|
||||||
@@ -555,6 +560,10 @@ class Ui_mainWindow(object):
|
|||||||
self.spreadShiftBox.setToolTip(QCoreApplication.translate("mainWindow", u"Shift first page to opposite side in landscape for two page spread alignment", None))
|
self.spreadShiftBox.setToolTip(QCoreApplication.translate("mainWindow", u"Shift first page to opposite side in landscape for two page spread alignment", None))
|
||||||
#endif // QT_CONFIG(tooltip)
|
#endif // QT_CONFIG(tooltip)
|
||||||
self.spreadShiftBox.setText(QCoreApplication.translate("mainWindow", u"Spread shift", None))
|
self.spreadShiftBox.setText(QCoreApplication.translate("mainWindow", u"Spread shift", None))
|
||||||
|
#if QT_CONFIG(tooltip)
|
||||||
|
self.fileFusionBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p>Combines all selected files into a single file. (Helpful for combining chapters into volumes.)</p></body></html>", None))
|
||||||
|
#endif // QT_CONFIG(tooltip)
|
||||||
|
self.fileFusionBox.setText(QCoreApplication.translate("mainWindow", u"File Fusion", None))
|
||||||
#if QT_CONFIG(tooltip)
|
#if QT_CONFIG(tooltip)
|
||||||
self.upscaleBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Nothing<br/></span>Images smaller than device resolution will not be resized.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - Stretching<br/></span>Images smaller than device resolution will be resized. Aspect ratio will be not preserved.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Upscaling<br/></span>Images smaller than device resolution will be resized. Aspect ratio will be preserved.</p></body></html>", None))
|
self.upscaleBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Nothing<br/></span>Images smaller than device resolution will not be resized.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - Stretching<br/></span>Images smaller than device resolution will be resized. Aspect ratio will be not preserved.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Upscaling<br/></span>Images smaller than device resolution will be resized. Aspect ratio will be preserved.</p></body></html>", None))
|
||||||
#endif // QT_CONFIG(tooltip)
|
#endif // QT_CONFIG(tooltip)
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
################################################################################
|
################################################################################
|
||||||
## Form generated from reading UI file 'MetaEditor.ui'
|
## Form generated from reading UI file 'MetaEditor.ui'
|
||||||
##
|
##
|
||||||
## Created by: Qt User Interface Compiler version 6.9.0
|
## Created by: Qt User Interface Compiler version 6.9.1
|
||||||
##
|
##
|
||||||
## WARNING! All changes made in this file will be lost when recompiling UI file!
|
## WARNING! All changes made in this file will be lost when recompiling UI file!
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ from copy import copy
|
|||||||
from glob import glob, escape
|
from glob import glob, escape
|
||||||
from re import sub
|
from re import sub
|
||||||
from stat import S_IWRITE, S_IREAD, S_IEXEC
|
from stat import S_IWRITE, S_IREAD, S_IEXEC
|
||||||
|
from typing import List
|
||||||
from zipfile import ZipFile, ZIP_STORED, ZIP_DEFLATED
|
from zipfile import ZipFile, ZIP_STORED, ZIP_DEFLATED
|
||||||
from tempfile import mkdtemp, gettempdir, TemporaryFile
|
from tempfile import mkdtemp, gettempdir, TemporaryFile
|
||||||
from shutil import move, copytree, rmtree, copyfile
|
from shutil import move, copytree, rmtree, copyfile
|
||||||
@@ -36,6 +37,7 @@ from uuid import uuid4
|
|||||||
from natsort import os_sort_keygen
|
from natsort import os_sort_keygen
|
||||||
from slugify import slugify as slugify_ext
|
from slugify import slugify as slugify_ext
|
||||||
from PIL import Image, ImageFile
|
from PIL import Image, ImageFile
|
||||||
|
from pathlib import Path
|
||||||
from subprocess import STDOUT, PIPE, CalledProcessError
|
from subprocess import STDOUT, PIPE, CalledProcessError
|
||||||
from psutil import virtual_memory, disk_usage
|
from psutil import virtual_memory, disk_usage
|
||||||
from html import escape as hescape
|
from html import escape as hescape
|
||||||
@@ -1242,6 +1244,40 @@ def checkPre(source):
|
|||||||
raise UserWarning("Target directory is not writable.")
|
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]')
|
||||||
|
else:
|
||||||
|
fusion_path = first_path.parent.joinpath(first_path.name + ' [fused]')
|
||||||
|
print("Running Fusion")
|
||||||
|
|
||||||
|
for source in sources:
|
||||||
|
print(f"Processing {source}...")
|
||||||
|
checkPre(source)
|
||||||
|
print("Checking images...")
|
||||||
|
path = getWorkFolder(source)
|
||||||
|
pathfinder = os.path.join(path, "OEBPS", "Images")
|
||||||
|
sanitizeTree(pathfinder)
|
||||||
|
# TODO: remove flattenTree when subchapters are supported
|
||||||
|
flattenTree(pathfinder)
|
||||||
|
source_path = Path(source)
|
||||||
|
if source_path.is_file():
|
||||||
|
os.renames(pathfinder, fusion_path.joinpath(source_path.stem))
|
||||||
|
else:
|
||||||
|
os.renames(pathfinder, fusion_path.joinpath(source_path.name))
|
||||||
|
|
||||||
|
|
||||||
|
end = perf_counter()
|
||||||
|
print(f"makefusion: {end - start} seconds")
|
||||||
|
print("Combined File: "+ str(fusion_path))
|
||||||
|
|
||||||
|
return str(fusion_path)
|
||||||
|
|
||||||
|
|
||||||
def makeBook(source, qtgui=None):
|
def makeBook(source, qtgui=None):
|
||||||
start = perf_counter()
|
start = perf_counter()
|
||||||
global GUI
|
global GUI
|
||||||
|
|||||||
Reference in New Issue
Block a user