mirror of
https://github.com/ciromattia/kcc
synced 2026-05-10 09:42:25 +00:00
Compare commits
7 Commits
v7.3.0
...
revert-845
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
46a6103e19 | ||
|
|
24ab72fcbc | ||
|
|
4af6a75874 | ||
|
|
28b6188a3f | ||
|
|
f000af1207 | ||
|
|
299f916580 | ||
|
|
c39e403595 |
30
.travis.yml
30
.travis.yml
@@ -1,30 +0,0 @@
|
|||||||
matrix:
|
|
||||||
include:
|
|
||||||
- os: osx
|
|
||||||
language: generic
|
|
||||||
osx_image: xcode11.1
|
|
||||||
|
|
||||||
before_install:
|
|
||||||
- pip3 install --upgrade pip setuptools wheel
|
|
||||||
|
|
||||||
install:
|
|
||||||
- pip3 install -r requirements.txt
|
|
||||||
- pip3 install certifi https://github.com/pyinstaller/pyinstaller/archive/develop.zip
|
|
||||||
- npm install -g appdmg
|
|
||||||
|
|
||||||
script: python3 setup.py build_binary
|
|
||||||
|
|
||||||
before_deploy:
|
|
||||||
- shopt -s extglob
|
|
||||||
- rm -r dist/!(*.deb|*.dmg)
|
|
||||||
|
|
||||||
deploy:
|
|
||||||
provider: gcs
|
|
||||||
access_key_id: GOOG1EC62457RKUYFR2TIZUWV4EFSV2EP5LVLPPFXUAKADWJFDYPFW63BQSLA
|
|
||||||
secret_access_key:
|
|
||||||
secure: sxYjeho7U3im0Ezf6cz6TjYDiLvf0kAM2ETQHYoFNbD1VVvhJJyymDCnPH80zpFKmhc1MWTB6ndwsrPfcyZDLR2meSdWGPjZfFPY3RcrfImndKi7ln+mYQDBQ7W1lGit4YcH3Ju7LHceaTbRA7fVTX8pWKOcbXL2oM+lQxTJHH32+crVma+ChhbjzTWsSLRoakt3Nhiveec5p/qSW7AFe4Zq+b3C85IgwjSJI/xVwzaWrs6p915h1zZi7KL7YCMIxfQFrvRPFR2KTbh/DoLCCrqfbD4qh0PVy1li51Ac3hd/u3foiNnTNchzgE3Nv/nbKmtFU6huuLNgzkQGuLA+yn7mKYzBwA3ZmFgoimdH9+yRCMkZ8B5VHpvfN1hgpJcyEl1T98Kv4cdtRYNB4w9iAMy1qSVxhjeI+2rjuWGoXro0lU6L4LIRCOruY3AuLCAKG8Qw5Ak9ksmIKBhZ9soxpoIwu/TYDUQkFj29IrUQucg9TEp7uAoxu8/7EHxB7hWnBRaBAAQbMuIRg7yysT3FT0Os6SB0t9+RBsVMSPuIti9JJZ2Lu0uRI1+Se+g7ItzYtJoPhBJAzAa+J9OONj0RNj2z8Vq2oIBhH4z6b6zTRMVroos3cdfYl5qIKs9SQ7rmeHoPRROcqpCznsUZ/ESa4f2MewFU/7AYcEnCesZV4xg=
|
|
||||||
bucket: kcc-deploy
|
|
||||||
local-dir: dist
|
|
||||||
skip_cleanup: true
|
|
||||||
on:
|
|
||||||
repo: AcidWeb/KCC
|
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
ISC LICENSE
|
ISC LICENSE
|
||||||
|
|
||||||
Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
Copyright (c) 2012-2025 Ciro Mattia Gonano <ciromattia@gmail.com>
|
||||||
Copyright (c) 2013-2019 Paweł Jastrzębski <pawelj@iosphe.re>
|
Copyright (c) 2013-2019 Paweł Jastrzębski <pawelj@iosphe.re>
|
||||||
Copyright (c) 2021-2023 Darodi
|
Copyright (c) 2021-2023 Darodi (https://github.com/darodi)
|
||||||
|
Copyright (c) 2023-2025 Alex Xu (https://github.com/axu2)
|
||||||
|
|
||||||
Permission to use, copy, modify, and/or distribute this software for
|
Permission to use, copy, modify, and/or distribute this software for
|
||||||
any purpose with or without fee is hereby granted, provided that the
|
any purpose with or without fee is hereby granted, provided that the
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ It was initially developed for Kindle but since version 4.6 it outputs valid EPU
|
|||||||
actually a comic/manga to EPUB converter that every e-reader owner can happily use**_.
|
actually a comic/manga to EPUB converter that every e-reader owner can happily use**_.
|
||||||
It can also optionally optimize images by applying a number of transformations.
|
It can also optionally optimize images by applying a number of transformations.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
### A word of warning
|
### A word of warning
|
||||||
**KCC** _is not_ [Amazon's Kindle Comic Creator](http://www.amazon.com/gp/feature.html?ie=UTF8&docId=1001103761) nor is in any way endorsed by Amazon.
|
**KCC** _is not_ [Amazon's Kindle Comic Creator](http://www.amazon.com/gp/feature.html?ie=UTF8&docId=1001103761) nor is in any way endorsed by Amazon.
|
||||||
Amazon's tool is for comic publishers and involves a lot of manual effort, while **KCC** is for comic/manga readers.
|
Amazon's tool is for comic publishers and involves a lot of manual effort, while **KCC** is for comic/manga readers.
|
||||||
@@ -319,5 +321,5 @@ The app relies and includes the following scripts:
|
|||||||
Please check [wiki page](https://github.com/ciromattia/kcc/wiki/Known-issues).
|
Please check [wiki page](https://github.com/ciromattia/kcc/wiki/Known-issues).
|
||||||
|
|
||||||
## COPYRIGHT
|
## COPYRIGHT
|
||||||
Copyright (c) 2012-2023 Ciro Mattia Gonano, Paweł Jastrzębski and Darodi.
|
Copyright (c) 2012-2025 Ciro Mattia Gonano, Paweł Jastrzębski, Darodi and Alex Xu.
|
||||||
**KCC** is released under ISC LICENSE; see [LICENSE.txt](./LICENSE.txt) for further details.
|
**KCC** is released under ISC LICENSE; see [LICENSE.txt](./LICENSE.txt) for further details.
|
||||||
|
|||||||
14
appveyor.yml
14
appveyor.yml
@@ -1,14 +0,0 @@
|
|||||||
environment:
|
|
||||||
PYTHON: "C:\\Python37-x64"
|
|
||||||
|
|
||||||
install:
|
|
||||||
- set PATH="%PYTHON%\\Scripts";%PATH%
|
|
||||||
- "%PYTHON%\\python.exe -m pip install --upgrade pip setuptools wheel"
|
|
||||||
- "%PYTHON%\\python.exe -m pip install -r requirements.txt"
|
|
||||||
- "%PYTHON%\\python.exe -m pip install certifi https://github.com/pyinstaller/pyinstaller/archive/develop.zip"
|
|
||||||
|
|
||||||
build_script:
|
|
||||||
- "%PYTHON%\\python.exe setup.py build_binary"
|
|
||||||
|
|
||||||
artifacts:
|
|
||||||
- path: dist\KCC*
|
|
||||||
@@ -40,7 +40,7 @@ from subprocess import STDOUT, PIPE
|
|||||||
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
|
||||||
|
|
||||||
from .shared import available_archive_tools, getImageFileName, walkSort, walkLevel, sanitizeTrace, subprocess_run
|
from .shared import available_archive_tools, md5Checksum, getImageFileName, walkSort, walkLevel, sanitizeTrace, subprocess_run
|
||||||
from . import comic2panel
|
from . import comic2panel
|
||||||
from . import image
|
from . import image
|
||||||
from . import comicarchive
|
from . import comicarchive
|
||||||
@@ -78,6 +78,7 @@ def main(argv=None):
|
|||||||
|
|
||||||
|
|
||||||
def buildHTML(path, imgfile, imgfilepath):
|
def buildHTML(path, imgfile, imgfilepath):
|
||||||
|
imgfilepath = md5Checksum(imgfilepath)
|
||||||
filename = getImageFileName(imgfile)
|
filename = getImageFileName(imgfile)
|
||||||
deviceres = options.profileData[1]
|
deviceres = options.profileData[1]
|
||||||
if not options.noprocessing and "Rotated" in options.imgMetadata[imgfilepath]:
|
if not options.noprocessing and "Rotated" in options.imgMetadata[imgfilepath]:
|
||||||
@@ -424,6 +425,7 @@ def buildOPF(dstdir, title, filelist, cover=None):
|
|||||||
"</container>"])
|
"</container>"])
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
|
|
||||||
def buildEPUB(path, chapternames, tomenumber, ischunked):
|
def buildEPUB(path, chapternames, tomenumber, ischunked):
|
||||||
filelist = []
|
filelist = []
|
||||||
chapterlist = []
|
chapterlist = []
|
||||||
@@ -504,7 +506,6 @@ def buildEPUB(path, chapternames, tomenumber, ischunked):
|
|||||||
"display: none;\n",
|
"display: none;\n",
|
||||||
"}\n"])
|
"}\n"])
|
||||||
f.close()
|
f.close()
|
||||||
build_html_start = perf_counter()
|
|
||||||
for dirpath, dirnames, filenames in os.walk(os.path.join(path, 'OEBPS', 'Images')):
|
for dirpath, dirnames, filenames in os.walk(os.path.join(path, 'OEBPS', 'Images')):
|
||||||
chapter = False
|
chapter = False
|
||||||
dirnames, filenames = walkSort(dirnames, filenames)
|
dirnames, filenames = walkSort(dirnames, filenames)
|
||||||
@@ -514,12 +515,10 @@ def buildEPUB(path, chapternames, tomenumber, ischunked):
|
|||||||
'cover' + getImageFileName(afile)[1])
|
'cover' + getImageFileName(afile)[1])
|
||||||
options.covers.append((image.Cover(os.path.join(dirpath, afile), cover, options,
|
options.covers.append((image.Cover(os.path.join(dirpath, afile), cover, options,
|
||||||
tomenumber), options.uuid))
|
tomenumber), options.uuid))
|
||||||
if not chapter:
|
|
||||||
chapterlist.append((dirpath.replace('Images', 'Text'), afile))
|
|
||||||
chapter = True
|
|
||||||
filelist.append(buildHTML(dirpath, afile, os.path.join(dirpath, afile)))
|
filelist.append(buildHTML(dirpath, afile, os.path.join(dirpath, afile)))
|
||||||
build_html_end = perf_counter()
|
if not chapter:
|
||||||
print(f"buildHTML: {build_html_end - build_html_start} seconds")
|
chapterlist.append((dirpath.replace('Images', 'Text'), filelist[-1][1]))
|
||||||
|
chapter = True
|
||||||
# Overwrite chapternames if tree is flat and ComicInfo.xml has bookmarks
|
# Overwrite chapternames if tree is flat and ComicInfo.xml has bookmarks
|
||||||
if not chapternames and options.chapters and not ischunked:
|
if not chapternames and options.chapters and not ischunked:
|
||||||
chapterlist = []
|
chapterlist = []
|
||||||
@@ -567,13 +566,10 @@ def imgDirectoryProcessing(path):
|
|||||||
if GUI:
|
if GUI:
|
||||||
GUI.progressBarTick.emit(str(pagenumber))
|
GUI.progressBarTick.emit(str(pagenumber))
|
||||||
if len(work) > 0:
|
if len(work) > 0:
|
||||||
img_processing_start = perf_counter()
|
|
||||||
for i in work:
|
for i in work:
|
||||||
workerPool.apply_async(func=imgFileProcessing, args=(i,), callback=imgFileProcessingTick)
|
workerPool.apply_async(func=imgFileProcessing, args=(i,), callback=imgFileProcessingTick)
|
||||||
workerPool.close()
|
workerPool.close()
|
||||||
workerPool.join()
|
workerPool.join()
|
||||||
img_processing_end = perf_counter()
|
|
||||||
print(f"imgFileProcessing: {img_processing_end - img_processing_start} seconds")
|
|
||||||
if GUI and not GUI.conversionAlive:
|
if GUI and not GUI.conversionAlive:
|
||||||
rmtree(os.path.join(path, '..', '..'), True)
|
rmtree(os.path.join(path, '..', '..'), True)
|
||||||
raise UserWarning("Conversion interrupted.")
|
raise UserWarning("Conversion interrupted.")
|
||||||
@@ -813,7 +809,6 @@ def sanitizeTree(filetree):
|
|||||||
key = os.path.join(root, name)
|
key = os.path.join(root, name)
|
||||||
if key != newKey:
|
if key != newKey:
|
||||||
os.replace(key, newKey)
|
os.replace(key, newKey)
|
||||||
options.imgMetadata[newKey] = options.imgMetadata.pop(key)
|
|
||||||
for i, name in enumerate(dirs):
|
for i, name in enumerate(dirs):
|
||||||
tmpName = name
|
tmpName = name
|
||||||
slugified = slugify(name)
|
slugified = slugify(name)
|
||||||
@@ -825,10 +820,6 @@ def sanitizeTree(filetree):
|
|||||||
if key != newKey:
|
if key != newKey:
|
||||||
os.replace(key, newKey)
|
os.replace(key, newKey)
|
||||||
dirs[i] = newKey
|
dirs[i] = newKey
|
||||||
existingImgPathKeys = list(options.imgMetadata.keys())
|
|
||||||
for imgPath in existingImgPathKeys:
|
|
||||||
if imgPath.startswith(key):
|
|
||||||
options.imgMetadata[newKey + imgPath.removeprefix(key)] = options.imgMetadata.pop(imgPath)
|
|
||||||
return chapterNames
|
return chapterNames
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import io
|
|||||||
import os
|
import os
|
||||||
import mozjpeg_lossless_optimization
|
import mozjpeg_lossless_optimization
|
||||||
from PIL import Image, ImageOps, ImageStat, ImageChops, ImageFilter
|
from PIL import Image, ImageOps, ImageStat, ImageChops, ImageFilter
|
||||||
|
from .shared import md5Checksum
|
||||||
from .page_number_crop_alg import get_bbox_crop_margin_page_number, get_bbox_crop_margin
|
from .page_number_crop_alg import get_bbox_crop_margin_page_number, get_bbox_crop_margin
|
||||||
from .inter_panel_crop_alg import crop_empty_inter_panel
|
from .inter_panel_crop_alg import crop_empty_inter_panel
|
||||||
|
|
||||||
@@ -320,7 +321,7 @@ class ComicPage:
|
|||||||
output_jpeg_file.write(output_jpeg_bytes)
|
output_jpeg_file.write(output_jpeg_bytes)
|
||||||
else:
|
else:
|
||||||
self.image.save(self.targetPath, 'JPEG', optimize=1, quality=85)
|
self.image.save(self.targetPath, 'JPEG', optimize=1, quality=85)
|
||||||
return [self.targetPath, flags, self.orgPath]
|
return [md5Checksum(self.targetPath), flags, self.orgPath]
|
||||||
except IOError as err:
|
except IOError as err:
|
||||||
raise RuntimeError('Cannot save image. ' + str(err))
|
raise RuntimeError('Cannot save image. ' + str(err))
|
||||||
|
|
||||||
|
|||||||
@@ -75,6 +75,16 @@ def walkLevel(some_dir, level=1):
|
|||||||
del dirs[:]
|
del dirs[:]
|
||||||
|
|
||||||
|
|
||||||
|
def md5Checksum(fpath):
|
||||||
|
with open(fpath, 'rb') as fh:
|
||||||
|
m = md5()
|
||||||
|
while True:
|
||||||
|
data = fh.read(8192)
|
||||||
|
if not data:
|
||||||
|
break
|
||||||
|
m.update(data)
|
||||||
|
return m.hexdigest()
|
||||||
|
|
||||||
|
|
||||||
def sanitizeTrace(traceback):
|
def sanitizeTrace(traceback):
|
||||||
return ''.join(format_tb(traceback))\
|
return ''.join(format_tb(traceback))\
|
||||||
|
|||||||
Reference in New Issue
Block a user