1
0
mirror of https://github.com/ciromattia/kcc synced 2026-07-11 15:33:17 +00:00

Compare commits

...

20 Commits

Author SHA1 Message Date
Alex Xu a52c0ce03a Merge pull request #1394 from ciromattia/axu2-patch-1
Clarify Kobo profile + EPUB -> KEPUB
2026-07-10 18:42:03 -07:00
Alex Xu 1c0506fe7d Clarify Kobo profile + EPUB -> KEPUB 2026-07-10 18:41:48 -07:00
Alex Xu 806c6232c3 bump to 10.4.0 2026-07-10 18:39:41 -07:00
Alex Xu 6f9f5067d8 Merge pull request #1384 from drshliapa/fix/912-preserve-comicinfo
add Keep ComicInfo.xml in CBZ output option
2026-07-10 18:38:05 -07:00
Alex Xu 11be0dffcc make it an option 2026-07-10 18:32:44 -07:00
Alex Xu 4c10569ab1 millisecond timestamp kindlegen log (#1393) 2026-07-10 17:47:34 -07:00
Alex Xu 2a5cd6718d new user first startup: default is Paperwhite 12th Gen, split and rotate, RTL (#1392) 2026-07-10 14:48:48 -07:00
Alex Xu fd1468904f stop webtoon unchecking automatically check customm autocontrast (#1391) 2026-07-10 14:26:41 -07:00
Alex Xu feec40ffc8 more detailed kindlegen warnings (#1390)
* show kindlegen warnings and errors

* show kindlegen warnings

* dump kindlegen logs to txt

* move warnings to end

* don't show webtoon cover warning

* fix typo

* add timestamp to kindlegen log dump

* double enter

* add TODO

* add more TODO

* fix comment

* final clean up
2026-07-10 13:57:20 -07:00
Marian Leontiev f6ae7661bc fix macOS app version showing 0.0.0 in Info.plist (#1385) 2026-07-09 15:25:42 -07:00
Alex Xu ca14a4c813 don't crash on empty nested folders (#1388) 2026-07-08 17:46:46 -07:00
Alex Xu 0c1071a358 fix Access is denied with read only input folder (2013 bug) (#1387)
* fix Access is denied on read only input folders

* minimize changes
2026-07-08 17:22:23 -07:00
Alex Xu 858251f509 show entire kindlegen error (#1386) 2026-07-07 10:02:26 -07:00
Marian Leontiev 3c66aa9a67 preserve ComicInfo.xml in CBZ output for Other profile 2026-07-05 21:07:26 +02:00
Aldijonas 077957e665 Rename 'cover.jpg' file to '##cover.jpg' (#1383) 2026-07-05 07:34:26 -07:00
Aldijonas c3f86e29c8 Rename cover.jpg to !cover.jpg in CBZ (#1381)
Change cover image filename from 'cover.jpg' to '!cover.jpg' in line 1907 for correct cover display when using CBZ file format
2026-07-02 16:41:37 -07:00
Nils Leo 72e1546c2c fix: enable unrar on all distros, not just Fedora (#1376)
* fix: enable unrar on all distros, not just Fedora

unrar was gated behind distro.id() == 'fedora', so on Debian/Ubuntu
the binary was installed but never invoked. Try unrar unconditionally
after 7z, with an optional rarfile Python fallback.

Fixes CBR extraction on non-Fedora Linux distributions.

* fix: gate unrar on Linux and drop unused distro dependency

Debian/Ubuntu's '7zip' package ships the upstream 7zz binary, which
excludes RAR support for licensing reasons, so 7z fails to read .cbr
(RAR) archives. unrar was installed but only invoked when
distro.id() == 'fedora', so on Debian it was never tried and extraction
failed.

Per maintainer feedback, gate unrar on platform.system() == 'Linux'
(not needed on Windows or macOS) and drop the rarfile PyPI fallback to
avoid a new dependency. Since the code no longer imports distro, also
remove it from the requirements files and setup.py.
2026-07-02 15:07:36 -07:00
sa-mi 544e866b51 fix crash in smart cover crop for landscape covers (#1379) 2026-07-01 21:30:08 -07:00
Alex Xu 363a36a764 reduce job list minimum height from 150 to 110 pixels (#1378) 2026-07-01 17:34:17 -07:00
Alex Xu bece5290a3 remove 2nd row of buttons (#1377) 2026-06-29 17:17:41 -07:00
14 changed files with 1804 additions and 1744 deletions
+3
View File
@@ -123,6 +123,8 @@ For flatpak, Docker, and AppImage versions, refer to the wiki: https://github.co
Going back a few pages and exiting and re-entering book should fix it temporarily. Going back a few pages and exiting and re-entering book should fix it temporarily.
- What output format should I use? - What output format should I use?
- MOBI for Kindles. CBZ for Kindle DX. CBZ for Koreader. KEPUB for Kobo. PDF for ReMarkable or Kindle Scribe 2025. - MOBI for Kindles. CBZ for Kindle DX. CBZ for Koreader. KEPUB for Kobo. PDF for ReMarkable or Kindle Scribe 2025.
- Where is KEPUB option?
- Choosing a Kobo profile and EPUB output will output KEPUB.
- All options have additional information in tooltips if you hover over the option. - All options have additional information in tooltips if you hover over the option.
- To get the converted book onto your Kindle/Kobo, just drag and drop the mobi/kepub into the documents folder on your Kindle/Kobo via USB - To get the converted book onto your Kindle/Kobo, just drag and drop the mobi/kepub into the documents folder on your Kindle/Kobo via USB
- Kindle panel view not working? - Kindle panel view not working?
@@ -293,6 +295,7 @@ OUTPUT SETTINGS:
-t TITLE, --title TITLE -t TITLE, --title TITLE
Comic title [Default=filename or directory name] Comic title [Default=filename or directory name]
--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] --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]
--keepcomicinfo Keep any original ComicInfo.xml files [Default=0]
-a AUTHOR, --author AUTHOR -a AUTHOR, --author AUTHOR
Author name [Default=KCC] Author name [Default=KCC]
--language EPUB language [Default=en-US] --language EPUB language [Default=en-US]
+961 -993
View File
File diff suppressed because it is too large Load Diff
+61
View File
@@ -0,0 +1,61 @@
# -*- mode: python ; coding: utf-8 -*-
# macOS GUI build, used by setup.py build_binary
import sys
sys.path.insert(0, SPECPATH)
from kindlecomicconverter import __version__
a = Analysis(
['kcc.py'],
pathex=[],
binaries=[],
datas=[],
hiddenimports=['_cffi_backend'],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
noarchive=False,
optimize=0,
)
pyz = PYZ(a.pure)
exe = EXE(
pyz,
a.scripts,
[],
exclude_binaries=True,
name='Kindle Comic Converter',
debug=False,
bootloader_ignore_signals=False,
strip=True,
upx=True,
console=False,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
icon=['icons/comic2ebook.icns'],
)
coll = COLLECT(
exe,
a.binaries,
a.datas,
strip=True,
upx=True,
upx_exclude=[],
name='Kindle Comic Converter',
)
app = BUNDLE(
coll,
name='Kindle Comic Converter.app',
icon='icons/comic2ebook.icns',
bundle_identifier=None,
info_plist={
'CFBundleShortVersionString': __version__,
'CFBundleVersion': __version__,
},
)
+12 -12
View File
@@ -346,6 +346,8 @@ class WorkerThread(QThread):
options.metadatatitle = 1 options.metadatatitle = 1
elif GUI.metadataTitleBox.checkState() == Qt.CheckState.Checked: elif GUI.metadataTitleBox.checkState() == Qt.CheckState.Checked:
options.metadatatitle = 2 options.metadatatitle = 2
if GUI.keepComicInfoBox.isChecked():
options.keepcomicinfo = True
if GUI.deleteBox.isChecked(): if GUI.deleteBox.isChecked():
options.delete = True options.delete = True
if GUI.tempDirBox.isChecked(): if GUI.tempDirBox.isChecked():
@@ -558,8 +560,6 @@ class WorkerThread(QThread):
MW.addMessage.emit('Created EPUB file was too big. Weird file structure?', 'error', False) MW.addMessage.emit('Created EPUB file was too big. Weird file structure?', 'error', False)
MW.addMessage.emit('EPUB file: ' + str(epubSize) + 'MB. Supported size: ~350MB.', 'error', MW.addMessage.emit('EPUB file: ' + str(epubSize) + 'MB. Supported size: ~350MB.', 'error',
False) False)
if self.kindlegenErrorCode[0] == 3221226505:
MW.addMessage.emit('Unknown Windows error. Possibly filepath too long?', 'error', False)
else: else:
for item in outputPath: for item in outputPath:
if GUI.targetDirectory and GUI.targetDirectory != os.path.dirname(item): if GUI.targetDirectory and GUI.targetDirectory != os.path.dirname(item):
@@ -750,7 +750,6 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
else: else:
status = True status = True
GUI.editorButton.setEnabled(status) GUI.editorButton.setEnabled(status)
GUI.wikiButton.setEnabled(status)
GUI.deviceBox.setEnabled(status) GUI.deviceBox.setEnabled(status)
GUI.defaultOutputFolderButton.setEnabled(status) GUI.defaultOutputFolderButton.setEnabled(status)
GUI.clearButton.setEnabled(status) GUI.clearButton.setEnabled(status)
@@ -839,7 +838,6 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
GUI.interPanelCropBox.setEnabled(True) GUI.interPanelCropBox.setEnabled(True)
GUI.autoLevelBox.setEnabled(True) GUI.autoLevelBox.setEnabled(True)
GUI.autocontrastBox.setEnabled(True) GUI.autocontrastBox.setEnabled(True)
GUI.autocontrastBox.setChecked(True)
def togglequalityBox(self, value): def togglequalityBox(self, value):
@@ -1113,6 +1111,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
'smartCoverCropBox': GUI.smartCoverCropBox.checkState(), 'smartCoverCropBox': GUI.smartCoverCropBox.checkState(),
'coverFillBox': GUI.coverFillBox.checkState(), 'coverFillBox': GUI.coverFillBox.checkState(),
'metadataTitleBox': GUI.metadataTitleBox.checkState(), 'metadataTitleBox': GUI.metadataTitleBox.checkState(),
'keepComicInfoBox': GUI.keepComicInfoBox.checkState(),
'mozJpegBox': GUI.mozJpegBox.checkState(), 'mozJpegBox': GUI.mozJpegBox.checkState(),
'forcePngRgbBox': GUI.forcePngRgbBox.checkState(), 'forcePngRgbBox': GUI.forcePngRgbBox.checkState(),
'webpBox': GUI.webpBox.checkState(), 'webpBox': GUI.webpBox.checkState(),
@@ -1221,11 +1220,14 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
self.defaultOutputFolder = str(self.settings.value('defaultOutputFolder', '', type=str)) self.defaultOutputFolder = str(self.settings.value('defaultOutputFolder', '', type=str))
if not os.path.exists(self.defaultOutputFolder): if not os.path.exists(self.defaultOutputFolder):
self.defaultOutputFolder = '' self.defaultOutputFolder = ''
self.lastDevice = self.settings.value('lastDevice', 0, type=int)
# default is Kindle Paperwhite 12th Gen
self.lastDevice = self.settings.value('lastDevice', 3, type=int)
self.currentFormat = self.settings.value('currentFormat', 0, type=int) self.currentFormat = self.settings.value('currentFormat', 0, type=int)
self.startNumber = self.settings.value('startNumber', 0, type=int) self.startNumber = self.settings.value('startNumber', 0, type=int)
self.windowSize = self.settings.value('windowSize', '0x0', type=str) self.windowSize = self.settings.value('windowSize', '0x0', type=str)
default_options = {'gammaSlider': 0, 'croppingBox': 2, 'croppingPowerSlider': 100} default_options = {'gammaSlider': 0, 'croppingBox': 2, 'croppingPowerSlider': 100, 'rotateBox': 1, 'mangaBox': 2}
try: try:
self.options = self.settings.value('options', default_options) self.options = self.settings.value('options', default_options)
except Exception: except Exception:
@@ -1252,7 +1254,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
if self.windowSize == '0x0': if self.windowSize == '0x0':
MW.resize(500, 500) MW.resize(500, 500)
elif sys.platform.startswith('darwin'): elif sys.platform.startswith('darwin'):
for element in ['editorButton', 'wikiButton', 'defaultOutputFolderButton', 'clearButton', 'fileButton', 'deviceBox', for element in ['editorButton', 'defaultOutputFolderButton', 'clearButton', 'fileButton', 'deviceBox',
'convertButton', 'formatBox']: 'convertButton', 'formatBox']:
getattr(GUI, element).setMinimumSize(QSize(0, 0)) getattr(GUI, element).setMinimumSize(QSize(0, 0))
GUI.gridLayout.setContentsMargins(-1, -1, -1, -1) GUI.gridLayout.setContentsMargins(-1, -1, -1, -1)
@@ -1433,8 +1435,9 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
link_dict = { link_dict = {
'README': "https://github.com/ciromattia/kcc?tab=readme-ov-file#kcc", 'README': "https://github.com/ciromattia/kcc?tab=readme-ov-file#kcc",
'FAQ': "https://github.com/ciromattia/kcc/blob/master/README.md#faq", 'FAQ': "https://github.com/ciromattia/kcc/blob/master/README.md#faq",
'YOUTUBE': "https://youtu.be/IR2Fhcm9658?si=Z-2zzLaUFjmaEbrj", 'WIKI': "https://github.com/ciromattia/kcc/wiki",
'COMMISSIONS': "https://github.com/ciromattia/kcc?tab=readme-ov-file#commissions", 'TUTORIAL': "https://youtu.be/QQ6zJcMF2Iw?si=80rfm6DU6OUJdFqa",
'EMAIL': "https://github.com/ciromattia/kcc?tab=readme-ov-file#commissions",
'DONATE': "https://github.com/ciromattia/kcc/blob/master/README.md#issues--new-features--donations", 'DONATE': "https://github.com/ciromattia/kcc/blob/master/README.md#issues--new-features--donations",
'FORUM': "http://www.mobileread.com/forums/showthread.php?t=207461", 'FORUM': "http://www.mobileread.com/forums/showthread.php?t=207461",
'DISCORD': "https://discord.com/invite/qj7wpnUHav", 'DISCORD': "https://discord.com/invite/qj7wpnUHav",
@@ -1466,11 +1469,8 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
GUI.fileButton.clicked.connect(self.selectFile) GUI.fileButton.clicked.connect(self.selectFile)
GUI.directoryButton.clicked.connect(self.selectDir) GUI.directoryButton.clicked.connect(self.selectDir)
GUI.editorButton.clicked.connect(self.selectFileMetaEditor) GUI.editorButton.clicked.connect(self.selectFileMetaEditor)
GUI.wikiButton.clicked.connect(self.openWiki)
GUI.kofiButton.clicked.connect(self.openKofi) GUI.kofiButton.clicked.connect(self.openKofi)
GUI.humbleButton.clicked.connect(self.openHumble) GUI.humbleButton.clicked.connect(self.openHumble)
GUI.youtubeButton.clicked.connect(self.openYouTube)
GUI.discordButton.clicked.connect(self.openDiscord)
GUI.convertButton.clicked.connect(self.convertStart) GUI.convertButton.clicked.connect(self.convertStart)
GUI.gammaSlider.valueChanged.connect(self.changeGamma) GUI.gammaSlider.valueChanged.connect(self.changeGamma)
GUI.gammaBox.stateChanged.connect(self.togglegammaBox) GUI.gammaBox.stateChanged.connect(self.togglegammaBox)
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,4 +1,4 @@
__version__ = '10.3.0' __version__ = '10.4.0'
__license__ = 'ISC' __license__ = 'ISC'
__copyright__ = '2012-2022, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>, darodi' __copyright__ = '2012-2022, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>, darodi'
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'
+58 -10
View File
@@ -19,6 +19,7 @@
# #
from collections import Counter from collections import Counter
from datetime import datetime
import os import os
import pathlib import pathlib
import re import re
@@ -1103,6 +1104,7 @@ def getOutputFilename(srcpath, wantedname, ext, tomenumber):
def getMetadata(path, originalpath): def getMetadata(path, originalpath):
xmlPath = os.path.join(path, 'ComicInfo.xml') xmlPath = os.path.join(path, 'ComicInfo.xml')
options.comicinfo_chapters = [] options.comicinfo_chapters = []
options.comicinfo_xml = None
options.summary = '' options.summary = ''
titleSuffix = '' titleSuffix = ''
options.volume = '' options.volume = ''
@@ -1159,6 +1161,10 @@ def getMetadata(path, originalpath):
options.summary = xml.data['Summary'] options.summary = xml.data['Summary']
if xml.data['Series']: if xml.data['Series']:
options.series = xml.data['Series'] options.series = xml.data['Series']
# ComicInfo.xml in output may break readers like the Kobo native CBZ reader
if options.keepcomicinfo and options.format == 'CBZ':
with open(xmlPath, 'rb') as f:
options.comicinfo_xml = f.read()
os.remove(xmlPath) os.remove(xmlPath)
if originalpath.lower().endswith('.pdf'): if originalpath.lower().endswith('.pdf'):
@@ -1201,11 +1207,19 @@ def removeNonImages(filetree):
os.remove(os.path.join(root, name)) os.remove(os.path.join(root, name))
# remove empty nested folders # remove empty nested folders
for root, dirs, files in os.walk(filetree, False): for root, dirs, files in os.walk(filetree, False):
if not files and not dirs: if not os.listdir(root):
os.rmdir(root) os.rmdir(root)
if not os.listdir(Path(filetree).parent): if not os.listdir(Path(filetree).parent):
raise UserWarning('No images detected, nested archives are not supported.') warning = [
'No images detected.',
'',
'Possible causes:',
'',
'1) Incompatible image file extension like .jxl. Convert to .png first outside of KCC.',
'2) Nested archive: Either extract the nested archive outside of KCC or use File Fusion option.',
]
raise RuntimeError('\n'.join(warning))
def sanitizeTree(filetree, prefix='kcc'): def sanitizeTree(filetree, prefix='kcc'):
@@ -1254,6 +1268,7 @@ def flattenTree(filetree):
def sanitizePermissions(filetree): def sanitizePermissions(filetree):
os.chmod(filetree, S_IWRITE | S_IREAD | S_IEXEC)
for root, dirs, files in os.walk(filetree, False): for root, dirs, files in os.walk(filetree, False):
for name in files: for name in files:
os.chmod(os.path.join(root, name), S_IWRITE | S_IREAD) os.chmod(os.path.join(root, name), S_IWRITE | S_IREAD)
@@ -1475,6 +1490,8 @@ def makeParser():
output_options.add_argument("--metadatatitle", type=int, dest="metadatatitle", default=0, output_options.add_argument("--metadatatitle", type=int, dest="metadatatitle", default=0,
help="Write title using ComicInfo.xml or other embedded metadata. 1: Combine Title with default schema " help="Write title using ComicInfo.xml or other embedded metadata. 1: Combine Title with default schema "
"2: Use Title only") "2: Use Title only")
output_options.add_argument("--keepcomicinfo", type=int, dest="keepcomicinfo", default=0,
help="Keep any original ComicInfo.xml files")
output_options.add_argument("-a", "--author", action="store", dest="author", default="defaultauthor", output_options.add_argument("-a", "--author", action="store", dest="author", default="defaultauthor",
help="Author name [Default=KCC]") help="Author name [Default=KCC]")
output_options.add_argument("--language", action="store", dest="language", default="en-US", output_options.add_argument("--language", action="store", dest="language", default="en-US",
@@ -1904,7 +1921,10 @@ def makeBook(source, qtgui=None, job_progress=''):
else: else:
filepath.append(getOutputFilename(source, options.output, '.cbz', '')) filepath.append(getOutputFilename(source, options.output, '.cbz', ''))
if cover and cover.smartcover: if cover and cover.smartcover:
cover.save_to_folder(os.path.join(tome, 'OEBPS', 'Images', 'cover.jpg'), tomeNumber, len(tomes)) cover.save_to_folder(os.path.join(tome, 'OEBPS', 'Images', '##cover.jpg'), tomeNumber, len(tomes))
if options.comicinfo_xml:
with open(os.path.join(tome, 'OEBPS', 'Images', 'ComicInfo.xml'), 'wb') as xmlOutput:
xmlOutput.write(options.comicinfo_xml)
makeZIP(filepath[-1], os.path.join(tome, "OEBPS", "Images"), job_progress) makeZIP(filepath[-1], os.path.join(tome, "OEBPS", "Images"), job_progress)
elif options.format == 'PDF': elif options.format == 'PDF':
print(f"{job_progress}Creating PDF file with PyMuPDF...") print(f"{job_progress}Creating PDF file with PyMuPDF...")
@@ -1983,8 +2003,14 @@ def makeMOBIWorkerTick(output):
makeMOBIWorkerOutput.append(output) makeMOBIWorkerOutput.append(output)
if output[0] != 0: if output[0] != 0:
makeMOBIWorkerPool.terminate() makeMOBIWorkerPool.terminate()
for warning in output[3]:
print(warning)
if GUI: if GUI:
GUI.progressBarTick.emit('tick') GUI.progressBarTick.emit('tick')
if output[3]:
for warning in output[3]:
GUI.addMessage.emit(warning, 'warning', False)
GUI.addMessage.emit('', '', False)
if not GUI.conversionAlive: if not GUI.conversionAlive:
makeMOBIWorkerPool.terminate() makeMOBIWorkerPool.terminate()
@@ -1994,8 +2020,10 @@ def makeMOBIWorker(item):
kindlegenErrorCode = 0 kindlegenErrorCode = 0
kindlegenError = '' kindlegenError = ''
try: try:
# TODO: This size check is incorrect, I think kindlegen increased the limit
if os.path.getsize(item) < 629145600: if os.path.getsize(item) < 629145600:
start = perf_counter() start = perf_counter()
# TODO: should anything be done with the kindlegen output during successes?
output = subprocess_run(['kindlegen', '-dont_append_source', '-locale', 'en', item], output = subprocess_run(['kindlegen', '-dont_append_source', '-locale', 'en', item],
stdout=PIPE, stderr=STDOUT, encoding='UTF-8', errors='ignore', check=True) stdout=PIPE, stderr=STDOUT, encoding='UTF-8', errors='ignore', check=True)
end = perf_counter() end = perf_counter()
@@ -2003,27 +2031,47 @@ def makeMOBIWorker(item):
else: else:
# ERROR: EPUB too big # ERROR: EPUB too big
kindlegenErrorCode = 23026 kindlegenErrorCode = 23026
return [kindlegenErrorCode, kindlegenError, item] return [kindlegenErrorCode, kindlegenError, item, []]
except CalledProcessError as err: except CalledProcessError as err:
warnings = []
for line in err.stdout.splitlines(): for line in err.stdout.splitlines():
# ERROR: Generic error # ERROR: Generic error
if "Error(" in line: if "Error(" in line:
kindlegenErrorCode = 1 kindlegenErrorCode = 1
kindlegenError = line kindlegenError = '\n\n'.join(warnings + [line, 'kindlegen logs dumped'])
try:
timestamp = datetime.now().isoformat(timespec='milliseconds').replace(':', '-').replace('.', '-')
with open(os.path.join(os.path.dirname(item), f'kindlegen-log-{timestamp}.txt'), 'w') as f:
f.write(err.stdout)
except Exception as e:
print(e)
# examples
# Warning(prcgen):W14019: Cover is too small
if "Warning(" in line:
if ":W14016: Cover not specified" in line and options.webtoon:
pass
else:
warnings.append(line)
# ERROR: EPUB too big # ERROR: EPUB too big
if ":E23026:" in line: if ":E23026:" in line:
kindlegenErrorCode = 23026 kindlegenErrorCode = 23026
if ":E23028:" in line:
kindlegenErrorCode = 23028
if kindlegenErrorCode > 0: if kindlegenErrorCode > 0:
break break
if ":I1036: Mobi file built successfully" in line: if ":I1036: Mobi file built successfully" in line:
return [0, '', item] return [0, '', item, warnings]
if ":I1037: Mobi file built with WARNINGS!" in line: if ":I1037: Mobi file built with WARNINGS!" in line:
return [0, '', item] return [0, '', item, warnings]
# ERROR: KCC unknown generic error # ERROR: KCC unknown generic error
if kindlegenErrorCode == 0: if kindlegenErrorCode == 0:
kindlegenErrorCode = err.returncode kindlegenErrorCode = -1
kindlegenError = err.stdout if err.returncode == 3221226505:
return [kindlegenErrorCode, kindlegenError, item] kindlegenError = f'Error {err.returncode}: Unknown Windows error. Possibly filepath too long?'
else:
kindlegenError = f'Error {err.returncode}'
return [kindlegenErrorCode, kindlegenError, item, warnings]
def makeMOBI(work, qtgui=None): def makeMOBI(work, qtgui=None):
+6 -7
View File
@@ -22,7 +22,6 @@ from functools import cached_property, lru_cache
import os import os
from pathlib import Path from pathlib import Path
import platform import platform
import distro
from subprocess import STDOUT, PIPE, CalledProcessError from subprocess import STDOUT, PIPE, CalledProcessError
from xml.dom.minidom import parseString from xml.dom.minidom import parseString
from xml.parsers.expat import ExpatError from xml.parsers.expat import ExpatError
@@ -41,12 +40,12 @@ class ComicArchive:
self.dirname, self.basename = os.path.split(filepath) self.dirname, self.basename = os.path.split(filepath)
@cached_property @cached_property
def type(self): def type(self):
extraction_commands = [ extraction_commands = [
[SEVENZIP, 'l', '-y', '-p1', self.basename], [SEVENZIP, 'l', '-y', '-p1', self.basename],
] ]
if distro.id() == 'fedora' or distro.like() == 'fedora': if platform.system() == 'Linux':
extraction_commands.append( extraction_commands.append(
['unrar', 'l', '-y', '-p1', self.basename], ['unrar', 'l', '-y', '-p1', self.basename],
) )
@@ -85,20 +84,20 @@ class ComicArchive:
extraction_commands.reverse() extraction_commands.reverse()
if distro.id() == 'fedora' or distro.like() == 'fedora': if platform.system() == 'Linux':
extraction_commands.append( extraction_commands.append(
['unrar', 'x', '-y', '-x__MACOSX', '-x.DS_Store', '-xthumbs.db', '-xThumbs.db', self.basename, targetdir] ['unrar', 'x', '-y', '-x__MACOSX', '-x.DS_Store', '-xthumbs.db', '-xThumbs.db', self.basename, targetdir]
) )
for cmd in extraction_commands: for cmd in extraction_commands:
try: try:
subprocess_run(cmd, capture_output=True, check=True, cwd=self.dirname) subprocess_run(cmd, capture_output=True, check=True, cwd=self.dirname)
return targetdir return targetdir
except FileNotFoundError: except FileNotFoundError:
missing.append(cmd[0]) missing.append(cmd[0])
except CalledProcessError: except CalledProcessError:
pass pass
if missing: if missing:
raise OSError(f'Extraction failed, install <a href="https://github.com/ciromattia/kcc#7-zip">specialized extraction software.</a> ') raise OSError(f'Extraction failed, install <a href="https://github.com/ciromattia/kcc#7-zip">specialized extraction software.</a> ')
else: else:
+1 -1
View File
@@ -648,7 +648,7 @@ class Cover:
if self.options.righttoleft: if self.options.righttoleft:
self.image = self.image.crop((w * .36, 0, w, h)) self.image = self.image.crop((w * .36, 0, w, h))
else: else:
self.image = self.image.crop((w, 0, .64 * w, h)) self.image = self.image.crop((0, 0, .64 * w, h))
def save_to_folder(self, target, tomeid, len_tomes=0): def save_to_folder(self, target, tomeid, len_tomes=0):
try: try:
-1
View File
@@ -5,7 +5,6 @@ python-slugify>=8.0.4
packaging>=26.2 packaging>=26.2
mozjpeg-lossless-optimization>=1.2.0 mozjpeg-lossless-optimization>=1.2.0
natsort>=8.4.0 natsort>=8.4.0
distro>=1.9.0
# Below requirements are compiled in Dockefile # Below requirements are compiled in Dockefile
# numpy==2.3.4 # numpy==2.3.4
# PyMuPDF==1.26.6 # PyMuPDF==1.26.6
-1
View File
@@ -6,6 +6,5 @@ python-slugify>=8.0.4
packaging>=26.2 packaging>=26.2
mozjpeg-lossless-optimization>=1.2.0 mozjpeg-lossless-optimization>=1.2.0
natsort>=8.4.0 natsort>=8.4.0
distro>=1.9.0
numpy<2 numpy<2
PyMuPDF==1.25.5 PyMuPDF==1.25.5
-1
View File
@@ -6,6 +6,5 @@ python-slugify>=8.0.4
packaging>=26.2 packaging>=26.2
mozjpeg-lossless-optimization>=1.2.0 mozjpeg-lossless-optimization>=1.2.0
natsort>=8.4.0 natsort>=8.4.0
distro>=1.9.0
numpy==1.23.5 numpy==1.23.5
PyMuPDF>=1.16 PyMuPDF>=1.16
-1
View File
@@ -6,6 +6,5 @@ python-slugify>=8.0.4,<9.0.0
packaging>=26.2 packaging>=26.2
mozjpeg-lossless-optimization>=1.2.0 mozjpeg-lossless-optimization>=1.2.0
natsort>=8.4.0 natsort>=8.4.0
distro>=1.9.0
numpy>=1.22.4 numpy>=1.22.4
PyMuPDF>=1.18.0 PyMuPDF>=1.18.0
+1 -2
View File
@@ -38,7 +38,7 @@ class BuildBinaryCommand(setuptools.Command):
def run(self): def run(self):
VERSION = __version__ VERSION = __version__
if sys.platform == 'darwin': if sys.platform == 'darwin':
os.system('pyinstaller --hidden-import=_cffi_backend -y -D -i icons/comic2ebook.icns -n "Kindle Comic Converter" -w -s kcc.py') os.system('pyinstaller -y kcc-macos.spec')
# TODO /usr/bin/codesign --force -s "$MACOS_CERTIFICATE_NAME" --options runtime dist/Applications/Kindle\ Comic\ Converter.app -v # TODO /usr/bin/codesign --force -s "$MACOS_CERTIFICATE_NAME" --options runtime dist/Applications/Kindle\ Comic\ Converter.app -v
min_os = os.getenv('MACOSX_DEPLOYMENT_TARGET', '') min_os = os.getenv('MACOSX_DEPLOYMENT_TARGET', '')
if min_os.startswith('10.1'): if min_os.startswith('10.1'):
@@ -155,7 +155,6 @@ setuptools.setup(
'python-slugify>=1.2.1,<9.0.0', 'python-slugify>=1.2.1,<9.0.0',
'mozjpeg-lossless-optimization>=1.2.0', 'mozjpeg-lossless-optimization>=1.2.0',
'natsort>=8.4.0', 'natsort>=8.4.0',
'distro>=1.8.0',
'numpy>=1.22.4', 'numpy>=1.22.4',
'packaging>=23.2', 'packaging>=23.2',
'PyMuPDF>=1.16.1', 'PyMuPDF>=1.16.1',