1
0
mirror of https://github.com/ciromattia/kcc synced 2026-06-28 09:14:07 +00:00

Compare commits

...

20 Commits

Author SHA1 Message Date
Alex Xu cab3703217 bump to 10.3.0 2026-06-26 10:23:51 -07:00
Alex Xu 3723bf9d52 add light novel mode (#1361)
* add a novel mode where it only resizes images

* add GUI

* cleanup

* fix typo

* fully cooked

* remove print

* clean up

* cook

* cook

* handle LA case

* cleanup
2026-06-26 10:23:28 -07:00
Alex Xu 2a6d61530f epub input: fix fusion (#1375) 2026-06-26 10:23:09 -07:00
Alex Xu 5396f1f9c4 name output epub/cbz directly (#1374) 2026-06-24 21:22:49 -07:00
Alex Xu f1b58c83d6 Replace copyfile + remove with move (#1373)
* remove mobiPath toclean

* remove copyfile _comic.zip
2026-06-24 18:58:27 -07:00
Alex Xu 0f009755b1 store settings separately 2026-06-23 17:37:46 -07:00
Alex Xu ee5bd150e5 add force ebok option 2026-06-23 17:37:46 -07:00
Alex Xu a55c0ddb08 add epub language option (#1371) 2026-06-23 13:29:10 -07:00
Alex Xu 799961407e re-arrange options into 4 columns (#1370)
* re-arrange options into 4 columns

* put delete input at the top
2026-06-22 22:27:00 -07:00
Alex Xu bc28df1f53 add invert direction and vertical 4 panel options (#1369) 2026-06-22 17:31:12 -07:00
Alex Xu a8b2c055bf epub input: invert spread shift (#1368) 2026-06-22 17:17:22 -07:00
dependabot[bot] afa9c7e7e6 Update psutil requirement from >=5.9.5 to >=7.2.2 (#1358)
Updates the requirements on [psutil](https://github.com/giampaolo/psutil) to permit the latest version.
- [Changelog](https://github.com/giampaolo/psutil/blob/master/docs/changelog.rst)
- [Commits](https://github.com/giampaolo/psutil/compare/v5.9.5...v7.2.2)

---
updated-dependencies:
- dependency-name: psutil
  dependency-version: 7.2.2
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-22 14:04:31 -07:00
dependabot[bot] 1f1b9a37fa Update distro requirement from >=1.8.0 to >=1.9.0 (#1357)
Updates the requirements on [distro](https://github.com/python-distro/distro) to permit the latest version.
- [Release notes](https://github.com/python-distro/distro/releases)
- [Changelog](https://github.com/python-distro/distro/blob/master/CHANGELOG.md)
- [Commits](https://github.com/python-distro/distro/compare/v1.8.0...v1.9.0)

---
updated-dependencies:
- dependency-name: distro
  dependency-version: 1.9.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-22 14:04:15 -07:00
dependabot[bot] c4d9512cbc Bump actions/checkout from 6 to 7 (#1367)
Bumps [actions/checkout](https://github.com/actions/checkout) from 6 to 7.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-22 14:02:58 -07:00
Alex Xu 89fc6437dd don't crash if rosetta is not available on macOS (#1366)
* don't crash if rosetta is not available on macOS

* make error a dialog

* add newlines

* fix format

* modify strings
2026-06-20 17:55:04 -07:00
Alex Xu 1e57da08a9 time kindlegen (#1365) 2026-06-18 16:34:52 -07:00
Alex Xu b4ef37dbb9 bump Windows 7 numpy (#1362) 2026-05-31 18:43:10 -07:00
Alex Xu b95cf6e179 ignore exceptions when epub parsing (#1360)
* ignore exceptions when epub parsing

* Update comic2ebook.py

* Update comic2ebook.py
2026-05-26 09:13:22 -07:00
フィルターペーパー 08070cdd97 Fix fusion output location (#1355)
* Fix fusion output location

Use source folder when output folder is not specified

* undelete things
2026-05-25 16:41:36 -07:00
Alex Xu df3d174437 fusion temp file cleanup improvements (#1359) 2026-05-25 14:52:08 -07:00
18 changed files with 1571 additions and 1397 deletions
+1 -1
View File
@@ -38,7 +38,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v6
uses: actions/checkout@v7
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
+1 -1
View File
@@ -21,7 +21,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v7
- name: Login to GitHub Container Registry
uses: docker/login-action@v4
+1 -1
View File
@@ -25,7 +25,7 @@ jobs:
build:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
- name: Set up Python
uses: actions/setup-python@v6
with:
+1 -1
View File
@@ -30,7 +30,7 @@ jobs:
env:
MACOSX_DEPLOYMENT_TARGET: '14.0'
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
- name: Set up Python
uses: actions/setup-python@v6
with:
+1 -1
View File
@@ -31,7 +31,7 @@ jobs:
PYTHON_VERSION: 3.11.9
MACOSX_DEPLOYMENT_TARGET: '10.14'
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
- name: Get Python
run: curl https://www.python.org/ftp/python/3.11.9/python-3.11.9-macos11.pkg -o "python.pkg"
- name: Install Python
+1 -1
View File
@@ -35,7 +35,7 @@ jobs:
command: build_c2p
runs-on: windows-latest
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
- name: Set up Python
uses: actions/setup-python@v6
with:
+1 -1
View File
@@ -27,7 +27,7 @@ jobs:
env:
WINDOWS_7: 1
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
- name: Set up Python
uses: actions/setup-python@v6
with:
+5
View File
@@ -239,8 +239,12 @@ MAIN:
Device profile (Available options: K1, K2, K34, K578, KDX, KPW, KPW5, KV, KO, K11, KS, KoMT, KoG, KoGHD, KoA, KoAHD, KoAH2O, KoAO, KoN, KoC, KoCC, KoL, KoLC, KoF, KoS, KoE)
[Default=KV]
-m, --manga-style Manga style (right-to-left reading and splitting)
--lightnovel Only resize images and preserve original file structure.
--ebok Force EBOK tag instead of PDOC for MOBI
--invertdirection Invert page turn direction
-q, --hq Try to increase the quality of magnification
-2, --two-panel Display two not four panels in Panel View mode
--vertical4panel Show side panels first in virtual panel view
-w, --webtoon Webtoon processing mode
--ts TARGETSIZE, --targetsize TARGETSIZE
the maximal size of output file in MB. [Default=100MB for webtoon and 400MB for others]
@@ -291,6 +295,7 @@ OUTPUT SETTINGS:
--metadatatitle Write title using ComicInfo.xml or other embedded metadata. 0: Don't use Title from metadata 1: Combine Title with default schema 2: Use Title only [Default=0]
-a AUTHOR, --author AUTHOR
Author name [Default=KCC]
--language EPUB language [Default=en-US]
-f FORMAT, --format FORMAT
Output format (Available options: Auto, MOBI, EPUB, CBZ, PDF, KFX, MOBI+EPUB) [Default=Auto]
--nokepub If format is EPUB, output file with '.epub' extension rather than '.kepub.epub'
+787 -734
View File
File diff suppressed because it is too large Load Diff
+27 -12
View File
@@ -273,6 +273,12 @@ class WorkerThread(QThread):
options.format = gui_current_format
if GUI.mangaBox.isChecked():
options.righttoleft = True
if GUI.lightnovelBox.isChecked():
options.lightnovel = True
if GUI.ebokBox.isChecked():
options.ebok = True
if GUI.invertDirectionBox.isChecked():
options.invertdirection = True
if GUI.rotateBox.checkState() == Qt.CheckState.PartiallyChecked:
options.splitter = 2
elif GUI.rotateBox.checkState() == Qt.CheckState.Checked:
@@ -281,6 +287,8 @@ class WorkerThread(QThread):
options.autoscale = True
elif GUI.qualityBox.checkState() == Qt.CheckState.Checked:
options.hq = True
if GUI.vertical4PanelBox.isChecked():
options.vertical4panel = True
if GUI.webtoonBox.isChecked():
options.webtoon = True
if GUI.upscaleBox.checkState() == Qt.CheckState.PartiallyChecked:
@@ -379,6 +387,8 @@ class WorkerThread(QThread):
options.title = str(GUI.titleEdit.text())
if GUI.authorEdit.text():
options.author = str(GUI.authorEdit.text())
if GUI.languageEdit.text():
options.language = str(GUI.languageEdit.text())
if GUI.chunkSizeCheckBox.isChecked():
options.targetsize = int(GUI.chunkSizeBox.value())
@@ -393,7 +403,10 @@ class WorkerThread(QThread):
for job in currentJobs:
bookDir.append(job)
try:
fusion_source_parent = str(Path(bookDir[0]).parent)
comic2ebook.options = comic2ebook.checkOptions(copy(options))
if options.output is None:
options.output = fusion_source_parent
currentJobs.clear()
currentJobs.append(comic2ebook.makeFusion(bookDir))
MW.addMessage.emit('Created fusion at ' + currentJobs[0], 'info', False)
@@ -465,7 +478,7 @@ class WorkerThread(QThread):
MW.addMessage.emit('Creating PDF files... <b>Done!</b>', 'info', True)
else:
MW.addMessage.emit('Creating EPUB files... <b>Done!</b>', 'info', True)
if 'MOBI' in gui_current_format:
if 'MOBI' in gui_current_format and not options.lightnovel:
MW.progressBarTick.emit(f'{job_progress_number}Creating MOBI files')
MW.progressBarTick.emit(str(len(outputPath) * 2 + 1))
MW.progressBarTick.emit('tick')
@@ -506,7 +519,6 @@ class WorkerThread(QThread):
for item in outputPath:
GUI.progress.content = ''
mobiPath = item.replace('.epub', '.mobi')
os.remove(mobiPath + '_toclean')
if GUI.targetDirectory and GUI.targetDirectory != os.path.dirname(mobiPath):
try:
move(mobiPath, GUI.targetDirectory)
@@ -527,8 +539,6 @@ class WorkerThread(QThread):
mobiPath = item.replace('.epub', '.mobi')
if os.path.exists(mobiPath):
os.remove(mobiPath)
if os.path.exists(mobiPath + '_toclean'):
os.remove(mobiPath + '_toclean')
MW.addMessage.emit('Failed to process MOBI file!', 'error', False)
MW.addTrayMessage.emit('Failed to process MOBI file!', 'Critical')
else:
@@ -557,13 +567,6 @@ class WorkerThread(QThread):
move(item, GUI.targetDirectory)
except Exception:
pass
if options.filefusion:
for path in currentJobs:
if os.path.isfile(path):
os.remove(path)
elif os.path.isdir(path):
rmtree(path, True)
comic2ebook.checkPre('LLL-')
GUI.progress.content = ''
GUI.progress.stop()
MW.hideProgressBar.emit()
@@ -1084,8 +1087,13 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
self.settings.setValue('startNumber', self.startNumber + 1)
self.settings.setValue('windowSize', str(MW.size().width()) + 'x' + str(MW.size().height()))
self.settings.setValue('options', {'mangaBox': GUI.mangaBox.checkState(),
'lightnovelBox': GUI.lightnovelBox.checkState(),
'ebokBox': GUI.ebokBox.checkState(),
'invertDirectionBox': GUI.invertDirectionBox.checkState(),
'languageEdit': GUI.languageEdit.text(),
'rotateBox': GUI.rotateBox.checkState(),
'qualityBox': GUI.qualityBox.checkState(),
'vertical4PanelBox': GUI.vertical4PanelBox.checkState(),
'gammaBox': GUI.gammaBox.checkState(),
'autoLevelBox': GUI.autoLevelBox.checkState(),
'autocontrastBox': GUI.autocontrastBox.checkState(),
@@ -1193,6 +1201,11 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
self.kindleGen = False
if startup:
self.display_kindlegen_missing()
except OSError as e:
self.kindleGen = False
if startup:
error = f"kindlegen: {e.strerror}\n\n Re-install Rosetta/Kindle Previewer/other Intel app?\n\nPlease email Amazon to make Kindle Previewer Apple silicon native at amazon.com/kindle-help"
self.showDialog(error, 'error')
def __init__(self, kccapp, kccwindow):
global APP, MW, GUI
@@ -1202,7 +1215,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
self.setupUi(MW)
self.editor = KCCGUI_MetaEditor()
self.icons = Icons()
self.settings = QSettings('ciromattia', 'kcc9')
self.settings = QSettings('ciromattia', 'kcc10')
self.settingsVersion = self.settings.value('settingsVersion', '', type=str)
self.lastPath = self.settings.value('lastPath', '', type=str)
self.defaultOutputFolder = str(self.settings.value('defaultOutputFolder', '', type=str))
@@ -1516,6 +1529,8 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
GUI.widthBox.setValue(int(self.options[option]))
elif str(option) == "heightBox":
GUI.heightBox.setValue(int(self.options[option]))
elif str(option) == "languageEdit":
GUI.languageEdit.setText(str(self.options[option]))
elif str(option) == "gammaSlider":
if GUI.gammaSlider.isEnabled():
GUI.gammaSlider.setValue(int(self.options[option]))
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,4 +1,4 @@
__version__ = '10.2.0'
__version__ = '10.3.0'
__license__ = 'ISC'
__copyright__ = '2012-2022, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>, darodi'
__docformat__ = 'restructuredtext en'
+108 -46
View File
@@ -34,12 +34,12 @@ from stat import S_IWRITE, S_IREAD, S_IEXEC
from typing import List
from zipfile import ZipFile, ZIP_STORED
from tempfile import mkdtemp, gettempdir
from shutil import move, copytree, rmtree, copyfile
from shutil import move, copytree, rmtree
from multiprocessing import Pool, cpu_count
from uuid import uuid4
from natsort import os_sort_keygen, os_sorted
from slugify import slugify as slugify_ext
from PIL import Image, ImageFile
from PIL import Image, ImageFile, ImageOps
from pathlib import Path
from subprocess import STDOUT, PIPE, CalledProcessError
from psutil import virtual_memory, disk_usage
@@ -76,23 +76,19 @@ def main(argv=None):
print('No matching files found.')
return 1
if options.filefusion:
fusion_source_parent = str(Path(sources[0]).parent)
fusion_path = makeFusion(list(sources))
sources.clear()
sources.append(fusion_path)
for source in sources:
source = source.rstrip('\\').rstrip('/')
options = copy(args)
if options.filefusion and options.output is None:
options.output = fusion_source_parent
options = checkOptions(options)
print('Working on ' + source + '...')
makeBook(source)
if options.filefusion:
for path in sources:
if os.path.isfile(path):
os.remove(path)
elif os.path.isdir(path):
rmtree(path, True)
checkPre('LLL-')
return 0
@@ -230,7 +226,7 @@ def buildNCX(dstdir, title, chapters, chapternames):
ncxfile = os.path.join(dstdir, 'OEBPS', 'toc.ncx')
f = open(ncxfile, "w", encoding='UTF-8')
f.writelines(["<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n",
"<ncx version=\"2005-1\" xml:lang=\"en-US\" xmlns=\"http://www.daisy.org/z3986/2005/ncx/\">\n",
f"<ncx version=\"2005-1\" xml:lang=\"{options.language}\" xmlns=\"http://www.daisy.org/z3986/2005/ncx/\">\n",
"<head>\n",
"<meta name=\"dtb:uid\" content=\"urn:uuid:", options.uuid, "\"/>\n",
"<meta name=\"dtb:depth\" content=\"1\"/>\n",
@@ -296,10 +292,22 @@ def buildNAV(dstdir, title, chapters, chapternames):
def buildOPF(dstdir, title, filelist, originalpath, cover=None):
opffile = os.path.join(dstdir, 'OEBPS', 'content.opf')
deviceres = options.profileData[1]
if options.righttoleft:
writingmode = "horizontal-rl"
if options.vertical4panel:
writingmode = "vertical"
else:
writingmode = "horizontal-lr"
writingmode = "horizontal"
if options.invertdirection:
if options.righttoleft:
writingmode += "-lr"
else:
writingmode += "-rl"
else:
if options.righttoleft:
writingmode += "-rl"
else:
writingmode += "-lr"
f = open(opffile, "w", encoding='UTF-8')
f.writelines(["<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n",
"<package version=\"3.0\" unique-identifier=\"BookID\" ",
@@ -307,7 +315,7 @@ def buildOPF(dstdir, title, filelist, originalpath, cover=None):
"<metadata xmlns:opf=\"http://www.idpf.org/2007/opf\" ",
"xmlns:dc=\"http://purl.org/dc/elements/1.1/\">\n",
"<dc:title>", hescape(title), "</dc:title>\n",
"<dc:language>en-US</dc:language>\n",
f"<dc:language>{options.language}</dc:language>\n",
"<dc:identifier id=\"BookID\">urn:uuid:", options.uuid, "</dc:identifier>\n",
"<dc:contributor id=\"contributor\">KindleComicConverter-" + __version__ + "</dc:contributor>\n"])
if len(options.summary) > 0:
@@ -398,13 +406,22 @@ def buildOPF(dstdir, title, filelist, originalpath, cover=None):
else:
return ""
if options.righttoleft:
f.write("</manifest>\n<spine page-progression-direction=\"rtl\" toc=\"ncx\">\n")
pageside = "right"
if options.invertdirection:
if options.righttoleft:
f.write("</manifest>\n<spine page-progression-direction=\"ltr\" toc=\"ncx\">\n")
pageside = "left"
else:
f.write("</manifest>\n<spine page-progression-direction=\"rtl\" toc=\"ncx\">\n")
pageside = "right"
else:
f.write("</manifest>\n<spine page-progression-direction=\"ltr\" toc=\"ncx\">\n")
pageside = "left"
if originalpath.lower().endswith('.pdf'):
if options.righttoleft:
f.write("</manifest>\n<spine page-progression-direction=\"rtl\" toc=\"ncx\">\n")
pageside = "right"
else:
f.write("</manifest>\n<spine page-progression-direction=\"ltr\" toc=\"ncx\">\n")
pageside = "left"
if originalpath.lower().endswith('.pdf') or originalpath.lower().endswith('.epub'):
if pageside == "right":
pageside = "left"
else:
@@ -948,6 +965,8 @@ def getWorkFolder(afile, workdir=None):
try:
cbx = comicarchive.ComicArchive(afile)
path = cbx.extract(fullPath)
if options.lightnovel:
return workdir
sanitizePermissions(path)
tdir = os.listdir(fullPath)
@@ -979,10 +998,11 @@ def getWorkFolder(afile, workdir=None):
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:
try:
page_path = os.path.join(os.path.dirname(opf_path), manifest_dict[spine_item])
page = ET.parse(page_path)
except Exception:
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
@@ -1388,7 +1408,6 @@ def slugify(value, is_natural_sorted):
def makeZIP(zipfilename, basedir, job_progress='', isepub=False):
start = perf_counter()
zipfilename = os.path.abspath(zipfilename) + '.zip'
if SEVENZIP in available_archive_tools():
if isepub:
mimetypeFile = open(os.path.join(basedir, '!mimetype'), 'w')
@@ -1431,10 +1450,18 @@ def makeParser():
" [Default=KV]")
main_options.add_argument("-m", "--manga-style", action="store_true", dest="righttoleft", default=False,
help="Manga style (right-to-left reading and splitting)")
main_options.add_argument("--lightnovel", action="store_true", dest="lightnovel", default=False,
help="Only resize images and preserve original file structure.")
main_options.add_argument("--ebok", action="store_true", dest="ebok", default=False,
help="Force EBOK tag instead of PDOC for MOBI")
main_options.add_argument("--invertdirection", action="store_true", dest="invertdirection", default=False,
help="Invert page turn direction")
main_options.add_argument("-q", "--hq", action="store_true", dest="hq", default=False,
help="Try to increase the quality of magnification")
main_options.add_argument("-2", "--two-panel", action="store_true", dest="autoscale", default=False,
help="Display two not four panels in Panel View mode")
main_options.add_argument("--vertical4panel", action="store_true", dest="vertical4panel", default=False,
help="Display side panels first in virtual panel view")
main_options.add_argument("-w", "--webtoon", action="store_true", dest="webtoon", default=False,
help="Webtoon processing mode"),
main_options.add_argument("--ts", "--targetsize", type=int, dest="targetsize", default=None,
@@ -1450,6 +1477,8 @@ def makeParser():
"2: Use Title only")
output_options.add_argument("-a", "--author", action="store", dest="author", default="defaultauthor",
help="Author name [Default=KCC]")
output_options.add_argument("--language", action="store", dest="language", default="en-US",
help="EPUB language [Default=en-US]")
output_options.add_argument("-f", "--format", action="store", dest="format", default="Auto",
help="Output format (Available options: Auto, MOBI, EPUB, CBZ, KFX, MOBI+EPUB, PDF) "
"[Default=Auto]")
@@ -1557,6 +1586,9 @@ def checkOptions(options):
else:
options.isKobo = True
if options.lightnovel:
options.noKepub = True
if not options.iskindle and ('MOBI' in options.format or 'EPUB-200MB' in options.format or 'KFX' in options.format):
raise UserWarning('MOBI/Send to Kindle not supported for non-Kindle profiles')
@@ -1676,6 +1708,11 @@ def checkTools(source):
except (FileNotFoundError, CalledProcessError):
print('ERROR: KindleGen is missing!')
sys.exit(1)
except OSError as e:
print(f"kindlegen: {e.strerror}")
print('Re-install Rosetta/Kindle Previewer/other Intel app?')
print('Please email Amazon to make Kindle Previewer Apple silicon native at amazon.com/kindle-help')
sys.exit(1)
def checkPre(source='KCC-'):
@@ -1691,7 +1728,7 @@ def makeFusion(sources: List[str]):
start = perf_counter()
first_path = Path(sources[0])
if True:
if options.tempdir:
fusion_parent = first_path.parent
else:
# LLL is after KCC
@@ -1721,7 +1758,9 @@ def makeFusion(sources: List[str]):
else:
targetpath = fusion_path.joinpath(f'{prefix}{source_path.name}')
getWorkFolder(source, str(targetpath))
path = getWorkFolder(source, str(targetpath))
if path != str(targetpath):
move(os.path.join(path, 'OEBPS', 'Images'), targetpath)
sanitizeTree(targetpath, prefix='fusion')
# TODO: remove flattenTree when subchapters are supported
flattenTree(targetpath)
@@ -1747,6 +1786,35 @@ def makeBook(source, qtgui=None, job_progress=''):
print(f"{job_progress}Preparing source images...")
path = getWorkFolder(source)
print(f"{job_progress}Checking images...")
if options.lightnovel:
for root, _, files in os.walk(os.path.join(path, 'OEBPS', 'Images')):
for file in files:
_, ext = os.path.splitext(file)
if ext.lower() in ('.jpg', '.jpeg', '.png', '.webp', '.gif'):
with Image.open(os.path.join(root, file)) as img:
# TODO: detect BW images saved as RGB
if not options.forcecolor:
if img.mode == 'RGB':
img = img.convert('L')
elif img.mode == 'RGBA':
img = img.convert('LA')
x, y = image.ProfileData.Profiles[options.profile][1]
if options.iskindle:
x = min(x, 1920)
y = min(y, 1920)
if img.size[0] > x or img.size[1] > y:
img = ImageOps.contain(img, (x, y))
img.save(os.path.join(root, file), quality=options.jpegquality)
_, ext = os.path.splitext(source)
if ext != '.epub':
ext = '.cbz'
output_file = getOutputFilename(source, options.output, ext, '')
makeZIP(output_file, os.path.join(path, 'OEBPS', 'Images'), job_progress)
rmtree(path, True)
return [output_file]
getMetadata(os.path.join(path, "OEBPS", "Images"), source)
removeNonImages(os.path.join(path, "OEBPS", "Images"))
detectSuboptimalProcessing(os.path.join(path, "OEBPS", "Images"), source)
@@ -1837,7 +1905,7 @@ def makeBook(source, qtgui=None, job_progress=''):
filepath.append(getOutputFilename(source, options.output, '.cbz', ''))
if cover and cover.smartcover:
cover.save_to_folder(os.path.join(tome, 'OEBPS', 'Images', 'cover.jpg'), tomeNumber, len(tomes))
makeZIP(tome + '_comic', os.path.join(tome, "OEBPS", "Images"), job_progress)
makeZIP(filepath[-1], os.path.join(tome, "OEBPS", "Images"), job_progress)
elif options.format == 'PDF':
print(f"{job_progress}Creating PDF file with PyMuPDF...")
# determine output filename based on source and tome count
@@ -1856,19 +1924,11 @@ def makeBook(source, qtgui=None, job_progress=''):
else:
buildEPUB(tome, chapterNames, tomeNumber, False, cover, source, job_progress)
filepath.append(getOutputFilename(source, options.output, '.epub', ''))
makeZIP(tome + '_comic', tome, job_progress, True)
# Copy files to final destination (PDF files are already saved directly)
if options.format != 'PDF':
copyfile(tome + '_comic.zip', filepath[-1])
try:
os.remove(tome + '_comic.zip')
except FileNotFoundError:
# newly temporary created file is not found. It might have been already deleted
pass
makeZIP(filepath[-1], tome, job_progress, True)
rmtree(tome, True)
if GUI:
GUI.progressBarTick.emit('tick')
if not GUI and options.format == 'MOBI':
if not GUI and options.format == 'MOBI' and not options.lightnovel:
print(f"{job_progress}Creating MOBI files...")
work = []
for i in filepath:
@@ -1887,8 +1947,6 @@ def makeBook(source, qtgui=None, job_progress=''):
if not output[0]:
print(f'{job_progress}Error: Failed to tweak KindleGen output!')
return filepath
else:
os.remove(i.replace('.epub', '.mobi') + '_toclean')
if cover and k.path and k.coverSupport:
options.covers[filepath.index(i)][0].saveToKindle(k, options.covers[filepath.index(i)][1])
if options.delete:
@@ -1899,22 +1957,23 @@ def makeBook(source, qtgui=None, job_progress=''):
end = perf_counter()
print(f"{job_progress}makeBook: {end - start} seconds")
# Clean up temporary workspace
try:
rmtree(path, True)
except Exception:
pass
if options.filefusion:
rmtree(source, True)
checkPre('LLL-')
return filepath
def makeMOBIFix(item, uuid):
is_pdoc = options.profile in image.ProfileData.ProfilesKindlePDOC.keys()
if options.ebok:
is_pdoc = False
if not options.keep_epub:
os.remove(item)
mobiPath = item.replace('.epub', '.mobi')
move(mobiPath, mobiPath + '_toclean')
try:
dualmetafix.DualMobiMetaFix(mobiPath + '_toclean', mobiPath, bytes(uuid, 'UTF-8'), is_pdoc)
dualmetafix.DualMobiMetaFix(mobiPath, bytes(uuid, 'UTF-8'), is_pdoc)
return [True]
except Exception as err:
return [False, format(err)]
@@ -1936,8 +1995,11 @@ def makeMOBIWorker(item):
kindlegenError = ''
try:
if os.path.getsize(item) < 629145600:
start = perf_counter()
output = subprocess_run(['kindlegen', '-dont_append_source', '-locale', 'en', item],
stdout=PIPE, stderr=STDOUT, encoding='UTF-8', errors='ignore', check=True)
end = perf_counter()
print(f"kindlegen: {end - start} sec")
else:
# ERROR: EPUB too big
kindlegenErrorCode = 23026
+1 -2
View File
@@ -136,12 +136,11 @@ def del_exth(rec0, exth_num):
class DualMobiMetaFix:
def __init__(self, infile, outfile, asin, is_pdoc):
def __init__(self, outfile, asin, is_pdoc):
cdetype = b'EBOK'
if is_pdoc:
cdetype = b'PDOC'
shutil.copyfile(infile, outfile)
f = open(outfile, "r+b")
self.datain = mmap.mmap(f.fileno(), 0)
self.datain_rec0 = readsection(self.datain, 0)
+2 -2
View File
@@ -1,11 +1,11 @@
Pillow>=11.3.0
psutil>=5.9.5
psutil>=7.2.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
distro>=1.9.0
# Below requirements are compiled in Dockefile
# numpy==2.3.4
# PyMuPDF==1.26.6
+2 -2
View File
@@ -1,11 +1,11 @@
PySide6==6.4.3
Pillow>=11.3.0
psutil>=5.9.5
psutil>=7.2.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
distro>=1.9.0
numpy<2
PyMuPDF==1.25.5
+3 -3
View File
@@ -1,11 +1,11 @@
PySide6==6.1.3
Pillow>=9
psutil>=5.9.5
psutil>=7.2.2
requests>=2.32.4
python-slugify>=8.0.4
packaging>=26.2
mozjpeg-lossless-optimization>=1.2.0
natsort>=8.4.0
distro>=1.8.0
numpy==1.23.0
distro>=1.9.0
numpy==1.23.5
PyMuPDF>=1.16
+2 -2
View File
@@ -1,11 +1,11 @@
PySide6<6.10
Pillow>=11.3.0
psutil>=5.9.5
psutil>=7.2.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
distro>=1.9.0
numpy>=1.22.4
PyMuPDF>=1.18.0