mirror of
https://github.com/ciromattia/kcc
synced 2025-12-13 01:36:27 +00:00
1
.gitignore
vendored
1
.gitignore
vendored
@@ -15,3 +15,4 @@ setup.sh
|
||||
kindlecomicconverter/sentry.py
|
||||
build/
|
||||
.python-version
|
||||
KindleComicConverter.egg-info/
|
||||
|
||||
1
MANIFEST.in
Normal file
1
MANIFEST.in
Normal file
@@ -0,0 +1 @@
|
||||
exclude kindlecomicconverter/sentry.py
|
||||
154
README.md
154
README.md
@@ -1,4 +1,6 @@
|
||||
# KCC
|
||||
# KCC
|
||||
|
||||
[]() []() []()
|
||||
|
||||
**Kindle Comic Converter** is a Python app to convert comic/manga files or folders to EPUB, Panel View MOBI or E-Ink optimized CBZ.
|
||||
It was initially developed for Kindle but since version 4.6 it outputs valid EPUB 3.0 so _**despite its name, KCC is
|
||||
@@ -17,11 +19,11 @@ If you can fix an open issue, fork & make a pull request.
|
||||
|
||||
If you find **KCC** valuable you can consider donating to the authors:
|
||||
- Ciro Mattia Gonano:
|
||||
- [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=D8WNYNPBGDAS2)
|
||||
- [](http://flattr.com/thing/2260449/ciromattiakcc-on-GitHub)
|
||||
- [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=D8WNYNPBGDAS2)
|
||||
- [](http://flattr.com/thing/2260449/ciromattiakcc-on-GitHub)
|
||||
- Paweł Jastrzębski:
|
||||
- [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=YTTJ4LK2JDHPS)
|
||||
- Bitcoin: 1W15wwqsfd7wbaZ6wvSJf1LW1bz6q5L8b
|
||||
- [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=YTTJ4LK2JDHPS)
|
||||
- [](https://jastrzeb.ski/donate/)
|
||||
|
||||
## BINARY RELEASES
|
||||
You can find the latest released binary at the following links:
|
||||
@@ -29,20 +31,25 @@ You can find the latest released binary at the following links:
|
||||
- **Linux (Glibc 2.19+):** [http://kcc.iosphe.re/Linux/](http://kcc.iosphe.re/Linux/)
|
||||
- **OS X (10.9+):** [http://kcc.iosphe.re/OSX/](http://kcc.iosphe.re/OSX/)
|
||||
|
||||
## PYPI
|
||||
**KCC** is also available on PyPI.
|
||||
```
|
||||
pip install KindleComicConverter
|
||||
```
|
||||
|
||||
## DEPENDENCIES
|
||||
Following software is required to run Linux version of **KCC** and/or bare sources:
|
||||
- Python 3.3+
|
||||
- [PyQt](https://pypi.python.org/pypi/PyQt5) 5.6.0+
|
||||
- [Pillow](https://pypi.python.org/pypi/Pillow/) 3.2.0+
|
||||
- [psutil](https://pypi.python.org/pypi/psutil) 4.1.0+
|
||||
- [python-slugify](https://pypi.python.org/pypi/python-slugify) 1.2.0+
|
||||
- [raven](https://pypi.python.org/pypi/raven) 5.13.0+
|
||||
- [scandir](https://pypi.python.org/pypi/scandir) 1.2.0+ _(needed only when using Python 3.3 or 3.4)_
|
||||
- [PyQt5](https://pypi.python.org/pypi/PyQt5) 5.6.0+
|
||||
- [Pillow](https://pypi.python.org/pypi/Pillow/) 4.0.0+
|
||||
- [psutil](https://pypi.python.org/pypi/psutil) 5.0.0+
|
||||
- [python-slugify](https://pypi.python.org/pypi/python-slugify) 1.2.1+
|
||||
- [raven](https://pypi.python.org/pypi/raven) 6.0.0+
|
||||
|
||||
On Debian based distributions these two commands should install all needed dependencies:
|
||||
```
|
||||
sudo apt-get install python3 python3-dev python3-pip libpng-dev libjpeg-dev p7zip-full unrar
|
||||
sudo pip3 install --upgrade pillow python-slugify psutil scandir raven pyqt5
|
||||
sudo pip3 install --upgrade pillow python-slugify psutil pyqt5 raven
|
||||
```
|
||||
|
||||
### Optional dependencies
|
||||
@@ -163,35 +170,40 @@ The app relies and includes the following scripts:
|
||||
* [Kobo Aura ONE](http://kcc.iosphe.re/Samples/Ubunchu-KoAO.kepub.epub)
|
||||
|
||||
## CHANGELOG
|
||||
####5.3:
|
||||
#### 5.3.1:
|
||||
* Small increase of output quality
|
||||
* Improved error reporting
|
||||
* Internal changes and tweaks
|
||||
|
||||
#### 5.3:
|
||||
* Vastly improved output compatibility for non-Kindle devices
|
||||
* Enabled old pinch zoom for Kindle devices
|
||||
* Re-enabled Panel View support for Kindle Keyboard
|
||||
* Partially re-enabled OS X file association mechanism
|
||||
* Fixed multiple smaller issues
|
||||
|
||||
####5.2.1:
|
||||
#### 5.2.1:
|
||||
* Improved directory parsing
|
||||
* Tweaked margin detection algorithm
|
||||
* Improved error reporting
|
||||
|
||||
####5.2:
|
||||
#### 5.2:
|
||||
* Added new Panel View options
|
||||
* Implemented new margin detection algorithm
|
||||
* Removed HQ Panel View mode
|
||||
* Fixed multiple smaller issues
|
||||
|
||||
####5.1.3:
|
||||
#### 5.1.3:
|
||||
* Added Kobo Aura ONE profile
|
||||
* Fixed few small bugs
|
||||
|
||||
####5.1.2:
|
||||
#### 5.1.2:
|
||||
* Fixed error reporting
|
||||
|
||||
####5.1.1:
|
||||
#### 5.1.1:
|
||||
* Fixed multiple GUI bugs
|
||||
|
||||
####5.1:
|
||||
#### 5.1:
|
||||
* GUI now can be resized and high DPI support was somewhat improved
|
||||
* Added profile for Kindle Oasis
|
||||
* Implemented new error reporting mechanism
|
||||
@@ -199,55 +211,55 @@ The app relies and includes the following scripts:
|
||||
* Fixed permission issues on Windows
|
||||
* Fixed multiple smaller issues
|
||||
|
||||
####5.0.1:
|
||||
#### 5.0.1:
|
||||
* Fixed Panel View placement issues
|
||||
* Decreased application startup time
|
||||
* Fixed multiple smaller issues
|
||||
|
||||
####5.0:
|
||||
#### 5.0:
|
||||
* Major overhaul of internal mechanisms and GUI
|
||||
* Added cover upload feature
|
||||
* Tweaked Webtoon parsing mode
|
||||
* Fixed multiple smaller issues
|
||||
* Migrated build enviroment to PyInstaller
|
||||
|
||||
####4.6.5:
|
||||
#### 4.6.5:
|
||||
* Fixed multiple Windows and OS X issues
|
||||
* Allowed Linux release to use older PyQT5 version
|
||||
|
||||
####4.6.4:
|
||||
#### 4.6.4:
|
||||
* Fixed multiple Windows specific problems
|
||||
* Improved error handling
|
||||
* Improved color detection algorithm
|
||||
* New, slimmer OS X release
|
||||
|
||||
####4.6.3:
|
||||
#### 4.6.3:
|
||||
* Implemented remote bug reporting
|
||||
* Minor bug fixes and GUI tweaks
|
||||
|
||||
####4.6.2:
|
||||
#### 4.6.2:
|
||||
* Fixed critical MOBI header bug
|
||||
* Fixed metadata encoding error
|
||||
|
||||
####4.6.1:
|
||||
#### 4.6.1:
|
||||
* Fixed KEPUB TOC generator
|
||||
* Added warning about too small input files
|
||||
* ComicRack Summary metadata field is now parsed
|
||||
* Small tweaks of KEPUB output
|
||||
|
||||
####4.6:
|
||||
#### 4.6:
|
||||
* KEPUB is now default output for all Kobo profiles
|
||||
* EPUB output now produce fully valid EPUB 3.0.1
|
||||
* Added profile for Kindle Paperwhite 3
|
||||
* Dropped official support of all Kindle Fire models and Kindle for Android
|
||||
* Other minor tweaks
|
||||
|
||||
####4.5.1:
|
||||
#### 4.5.1:
|
||||
* Added Kobo Glo HD profile
|
||||
* Fixed RAR/CBR parsing anomalies
|
||||
* Minor bug fixes and tweaks
|
||||
|
||||
####4.5:
|
||||
#### 4.5:
|
||||
* Added simple ComicRack metadata editor
|
||||
* Re-enabled Manga Cover Database support
|
||||
* ComicRack bookmarks are now parsed
|
||||
@@ -256,61 +268,61 @@ The app relies and includes the following scripts:
|
||||
* Fixed sorting anomalies
|
||||
* Improved conversion speed
|
||||
|
||||
####4.4.1:
|
||||
#### 4.4.1:
|
||||
* Fixed problems with OSX GUI
|
||||
* Added one missing DLL to Windows installer
|
||||
|
||||
####4.4:
|
||||
#### 4.4:
|
||||
* Improved speed and quality of conversion
|
||||
* Added RAR5 support
|
||||
* Dropped BMP and TIFF support
|
||||
* Fixed some WebToon mode bugs
|
||||
* Fixed CBR parsing on OSX
|
||||
|
||||
####4.3.1:
|
||||
#### 4.3.1:
|
||||
* Fixed Kindle Voyage profile
|
||||
* Fixed some bugs in OS X release
|
||||
* CLI version now support multiple input files at once
|
||||
* Disabled MCB support
|
||||
* Other minor tweaks
|
||||
|
||||
####4.3:
|
||||
#### 4.3:
|
||||
* Added profiles for Kindle Voyage and Kobo Aura H2O
|
||||
* Added missing features to CLI version
|
||||
* Other minor bug fixes
|
||||
|
||||
####4.2.1:
|
||||
#### 4.2.1:
|
||||
* Improved margin color detection
|
||||
* Fixed random crashes of MOBI processing step
|
||||
* Fixed resizing problems in high quality mode
|
||||
* Fixed some MCD support bugs
|
||||
* Default output format for Kindle DX is now CBZ
|
||||
|
||||
####4.2:
|
||||
#### 4.2:
|
||||
* Added [Manga Cover Database](http://manga.joentjuh.nl/) support
|
||||
* Officially dropped Windows XP support
|
||||
* Fixed _Other_ profile
|
||||
* Fixed problems with page order on stock KOBO CBZ reader
|
||||
* Many other small bug fixes and tweaks
|
||||
|
||||
####4.1:
|
||||
#### 4.1:
|
||||
* Thanks to code contributed by Kevin Hendricks speed of MOBI creation was greatly increased
|
||||
* Improved performance on Windows
|
||||
* Improved MOBI splitting and changed maximal size of output file
|
||||
* Fixed _No optimization_ mode
|
||||
* Multiple small tweaks nad minor bug fixes
|
||||
|
||||
####4.0.2:
|
||||
#### 4.0.2:
|
||||
* Fixed some Windows and OSX specific bugs
|
||||
* Fixed problem with marigns when using HQ mode
|
||||
|
||||
####4.0.1:
|
||||
#### 4.0.1:
|
||||
* Fixed file lock problems that plagued some Windows users
|
||||
* Fixed content server failing to start on Windows
|
||||
* Improved performance of WebToon splitter
|
||||
* Tweaked margin color detection
|
||||
|
||||
####4.0:
|
||||
#### 4.0:
|
||||
* KCC now use Python 3.3 and Qt 5.2
|
||||
* Full UTF-8 awareness
|
||||
* CBZ output now support Manga mode
|
||||
@@ -322,13 +334,13 @@ The app relies and includes the following scripts:
|
||||
* Fixed OSX file association support
|
||||
* Many extensive internal changes and tweaks
|
||||
|
||||
####3.7.2:
|
||||
#### 3.7.2:
|
||||
* Fixed problems with HQ mode
|
||||
|
||||
####3.7.1:
|
||||
#### 3.7.1:
|
||||
* Hotfixed Kobo profiles
|
||||
|
||||
####3.7:
|
||||
#### 3.7:
|
||||
* Added profiles for KOBO devices
|
||||
* Improved Panel View support
|
||||
* Improved WebToon splitter
|
||||
@@ -337,14 +349,14 @@ The app relies and includes the following scripts:
|
||||
* Fixed stretching option
|
||||
* GUI tweaks and minor bugfixes
|
||||
|
||||
####3.6.2:
|
||||
#### 3.6.2:
|
||||
* Fixed previous PNG output fix
|
||||
* Fixed Panel View anomalies
|
||||
|
||||
####3.6.1:
|
||||
#### 3.6.1:
|
||||
* Fixed PNG output
|
||||
|
||||
####3.6:
|
||||
#### 3.6:
|
||||
* Increased quality of Panel View zoom
|
||||
* Creation of multipart MOBI output is now faster on machines with 4GB+ RAM
|
||||
* Automatic gamma correction now distinguishes color and grayscale images
|
||||
@@ -355,13 +367,13 @@ The app relies and includes the following scripts:
|
||||
* Fixed Kindle Fire HDX 7" output
|
||||
* Increased target resolution for Kindle DX/DXG CBZ output
|
||||
|
||||
####3.5:
|
||||
#### 3.5:
|
||||
* Added simple content server - Converted files can be now delivered wireless
|
||||
* Added proper Windows installer
|
||||
* Improved multiprocessing speed
|
||||
* GUI tweaks and minor bug fixes
|
||||
|
||||
####3.4:
|
||||
#### 3.4:
|
||||
* Improved PNG output
|
||||
* Increased quality of upscaling
|
||||
* Added support of file association - KCC can now open CBZ, CBR, CB7, ZIP, RAR, 7Z and PDF files directly
|
||||
@@ -370,7 +382,7 @@ The app relies and includes the following scripts:
|
||||
* Merged DX and DXG profiles
|
||||
* Many other minor bug fixes and GUI tweaks
|
||||
|
||||
####3.3:
|
||||
#### 3.3:
|
||||
* Margins are now automatically omitted in Panel View mode
|
||||
* Margin color fill is now autodetected
|
||||
* Created MOBI files are not longer marked as _Personal_ on newer Kindle models
|
||||
@@ -384,27 +396,27 @@ The app relies and includes the following scripts:
|
||||
* Windows release is now bundled with UnRAR and 7za
|
||||
* Small GUI tweaks
|
||||
|
||||
####3.2:
|
||||
#### 3.2:
|
||||
* Too big EPUB files are now splitted before conversion to MOBI
|
||||
* Added experimental parser of manga webtoons
|
||||
* Improved error handling
|
||||
|
||||
####3.2.1:
|
||||
#### 3.2.1:
|
||||
* Hotfixed crash occurring on OS with Russian locale
|
||||
|
||||
####3.1:
|
||||
#### 3.1:
|
||||
* Added profile: Kindle for Android
|
||||
* Add file/directory dialogs now support multiselect
|
||||
* Many small fixes and tweaks
|
||||
|
||||
####3.0:
|
||||
#### 3.0:
|
||||
* New QT GUI
|
||||
* Merge with AWKCC
|
||||
* Added ultra quality mode
|
||||
* Added support for custom width/height
|
||||
* Added option to disable color conversion
|
||||
|
||||
####2.10:
|
||||
#### 2.10:
|
||||
* Multiprocessing support
|
||||
* Kindle Fire support (color EPUB/MOBI)
|
||||
* Panel View support for horizontal content
|
||||
@@ -412,14 +424,14 @@ The app relies and includes the following scripts:
|
||||
* Disabled cropping and page number cutting for blank pages
|
||||
* Fixed some slugify issues with specific file naming conventions (#50, #51)
|
||||
|
||||
####2.9
|
||||
#### 2.9
|
||||
* Added support for generating a plain CBZ (skipping all the EPUB/MOBI generation) (#45)
|
||||
* Prevent output file overwriting the source one: if a duplicate name is detected, append _kcc to the name
|
||||
* Rarfile library updated to 2.6
|
||||
* Added GIF, TIFF and BMP to supported formats (#42)
|
||||
* Filenames slugifications (#28, #31, #9, #8)
|
||||
|
||||
####2.8
|
||||
#### 2.8
|
||||
* Updated rarfile library
|
||||
* Panel View support + HQ support (#36) - new option: --nopanelviewhq
|
||||
* Split profiles for K4NT and K4T
|
||||
@@ -428,7 +440,7 @@ The app relies and includes the following scripts:
|
||||
* Added generic CSS file
|
||||
* Optimized archive extraction for zip/rar files (#40)
|
||||
|
||||
####2.7
|
||||
#### 2.7
|
||||
* Lots of GUI improvements (#27, #13)
|
||||
* Added gamma support within --gamma option (defaults to profile-specified gamma) (#26, #27)
|
||||
* Added --nodithering option to prevent dithering optimizations (#27)
|
||||
@@ -439,57 +451,57 @@ The app relies and includes the following scripts:
|
||||
* Get filetype from magic number (#14)
|
||||
* PDF conversion works again
|
||||
|
||||
####2.6
|
||||
#### 2.6
|
||||
* Added --rotate option to rotate landscape images instead of splitting them (#16, #24)
|
||||
* Added --output option to customize EPUB output dir/file (#22)
|
||||
* Add rendition:layout and rendition:orientation EPUB meta tags (supported by new kindlegen 2.8)
|
||||
* Fixed natural sorting for files (#18)
|
||||
|
||||
####2.5
|
||||
#### 2.5
|
||||
* Added --black-borders option to set added borders black when page's ratio is not the device's one (#11).
|
||||
* Fixes EPUB containing zipped itself (#10)
|
||||
|
||||
####2.4
|
||||
#### 2.4
|
||||
* Use temporary directory as workdir (fixes converting from external volumes and zipfiles renaming)
|
||||
* Fixed "add folders" from GUI.
|
||||
|
||||
####2.3
|
||||
#### 2.3
|
||||
* Fixed win32 EPUB generation, folder handling, filenames with spaces and subfolders
|
||||
|
||||
####2.2:
|
||||
#### 2.2:
|
||||
* Added (valid!) EPUB 2.0 output
|
||||
* Rename .zip files to .cbz to avoid overwriting
|
||||
|
||||
####2.1
|
||||
#### 2.1
|
||||
* Added basic error reporting
|
||||
|
||||
####2.0
|
||||
#### 2.0
|
||||
* GUI! AppleScript is gone and Tk is used to provide cross-platform GUI support.
|
||||
|
||||
####1.5
|
||||
#### 1.5
|
||||
* Added subfolder support for multiple chapters.
|
||||
|
||||
####1.4.1
|
||||
#### 1.4.1
|
||||
* Fixed a serious bug on resizing when img ratio was bigger than device one
|
||||
|
||||
####1.4
|
||||
#### 1.4
|
||||
* Added some options for controlling image optimization
|
||||
* Further optimization (ImageOps, page numbering cut, autocontrast)
|
||||
|
||||
####1.3
|
||||
#### 1.3
|
||||
* Fixed an issue in OPF generation for device resolution
|
||||
* Reworked options system (call with -h option to get the inline help)
|
||||
|
||||
####1.2
|
||||
#### 1.2
|
||||
* Comic optimizations! Split pages not target-oriented (landscape with portrait target or portrait with landscape target), add palette and other image optimizations from Mangle. WARNING: PIL is required for all image mangling!
|
||||
|
||||
####1.1.1
|
||||
#### 1.1.1
|
||||
* Added support for CBZ/CBR files in Kindle Comic Converter
|
||||
|
||||
####1.1
|
||||
#### 1.1
|
||||
* Added support for CBZ/CBR files in comic2ebook.py
|
||||
|
||||
####1.0
|
||||
#### 1.0
|
||||
* Initial version
|
||||
|
||||
## PRIVACY
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
# acidweb/kcc
|
||||
FROM debian:jessie
|
||||
FROM debian:stretch
|
||||
MAINTAINER Paweł Jastrzębski <pawelj@iosphe.re>
|
||||
|
||||
ADD ./Build /Build
|
||||
|
||||
RUN printf "deb http://httpredir.debian.org/debian stretch main" > /etc/apt/sources.list.d/stretch.list
|
||||
RUN printf "Package: *\nPin: release a=testing\nPin-Priority: 400\n" > /etc/apt/preferences.d/stretch.pref
|
||||
RUN apt-get update && apt-get -y dist-upgrade
|
||||
RUN apt-get -y install build-essential curl ruby ruby-dev libpng-dev libjpeg-dev
|
||||
RUN apt-get -y -t testing install python3 python3-dev python3-pyqt5
|
||||
RUN apt-get -y install build-essential curl ruby ruby-dev libpng-dev libjpeg-dev python3 python3-dev python3-pyqt5
|
||||
RUN curl https://bootstrap.pypa.io/get-pip.py | python3
|
||||
RUN apt-get clean -y && apt-get autoclean -y && apt-get autoremove -y && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
||||
|
||||
|
||||
@@ -23,14 +23,9 @@ if sys.version_info[0] != 3:
|
||||
print('ERROR: This is Python 3 script!')
|
||||
exit(1)
|
||||
|
||||
from kindlecomicconverter.shared import dependencyCheck
|
||||
dependencyCheck(2)
|
||||
|
||||
from multiprocessing import freeze_support
|
||||
from kindlecomicconverter import __version__
|
||||
from kindlecomicconverter.comic2ebook import main
|
||||
from kindlecomicconverter.startup import startC2E
|
||||
|
||||
if __name__ == "__main__":
|
||||
freeze_support()
|
||||
print('comic2ebook v' + __version__ + ' - Written by Ciro Mattia Gonano and Pawel Jastrzebski.')
|
||||
sys.exit(main(sys.argv[1:]))
|
||||
startC2E()
|
||||
|
||||
@@ -23,14 +23,9 @@ if sys.version_info[0] != 3:
|
||||
print('ERROR: This is Python 3 script!')
|
||||
exit(1)
|
||||
|
||||
from kindlecomicconverter.shared import dependencyCheck
|
||||
dependencyCheck(1)
|
||||
|
||||
from multiprocessing import freeze_support
|
||||
from kindlecomicconverter import __version__
|
||||
from kindlecomicconverter.comic2panel import main
|
||||
from kindlecomicconverter.startup import startC2P
|
||||
|
||||
if __name__ == "__main__":
|
||||
freeze_support()
|
||||
print('comic2panel v' + __version__ + ' - Written by Ciro Mattia Gonano and Pawel Jastrzebski.')
|
||||
sys.exit(main(sys.argv[1:]))
|
||||
startC2P()
|
||||
2
kcc.iss
2
kcc.iss
@@ -1,5 +1,5 @@
|
||||
#define MyAppName "Kindle Comic Converter"
|
||||
#define MyAppVersion "5.3.0"
|
||||
#define MyAppVersion "5.3.1"
|
||||
#define MyAppPublisher "Ciro Mattia Gonano, Paweł Jastrzębski"
|
||||
#define MyAppURL "http://kcc.iosphe.re/"
|
||||
#define MyAppExeName "KCC.exe"
|
||||
|
||||
20
kcc.py
20
kcc.py
@@ -63,24 +63,10 @@ if getattr(sys, 'frozen', False):
|
||||
except:
|
||||
pass
|
||||
|
||||
from kindlecomicconverter.shared import dependencyCheck
|
||||
dependencyCheck(3)
|
||||
|
||||
from multiprocessing import freeze_support
|
||||
from kindlecomicconverter import KCC_gui
|
||||
from kindlecomicconverter.startup import start
|
||||
|
||||
if __name__ == "__main__":
|
||||
freeze_support()
|
||||
os.environ['QT_AUTO_SCREEN_SCALE_FACTOR'] = "1"
|
||||
KCCAplication = KCC_gui.QApplicationMessaging(sys.argv)
|
||||
if KCCAplication.isRunning():
|
||||
if len(sys.argv) > 1:
|
||||
KCCAplication.sendMessage(sys.argv[1])
|
||||
else:
|
||||
KCCAplication.sendMessage('ARISE')
|
||||
else:
|
||||
KCCWindow = KCC_gui.QMainWindowKCC()
|
||||
KCCUI = KCC_gui.KCCGUI(KCCAplication, KCCWindow)
|
||||
if len(sys.argv) > 1:
|
||||
KCCUI.handleMessage(sys.argv[1])
|
||||
sys.exit(KCCAplication.exec_())
|
||||
start()
|
||||
|
||||
|
||||
@@ -26,12 +26,12 @@ from shutil import move
|
||||
from subprocess import STDOUT, PIPE
|
||||
from PyQt5 import QtGui, QtCore, QtWidgets, QtNetwork
|
||||
from xml.dom.minidom import parse
|
||||
from xml.sax.saxutils import escape
|
||||
from psutil import Popen, Process
|
||||
from copy import copy
|
||||
from distutils.version import StrictVersion
|
||||
from xml.sax.saxutils import escape
|
||||
from raven import Client
|
||||
from .shared import md5Checksum, HTMLStripper, sanitizeTrace, saferRemove
|
||||
from .shared import md5Checksum, HTMLStripper, sanitizeTrace
|
||||
from . import __version__
|
||||
from . import comic2ebook
|
||||
from . import metadata
|
||||
@@ -334,7 +334,7 @@ class WorkerThread(QtCore.QThread):
|
||||
if 'outputPath' in locals():
|
||||
for item in outputPath:
|
||||
if os.path.exists(item):
|
||||
saferRemove(item)
|
||||
os.remove(item)
|
||||
self.clean()
|
||||
return
|
||||
if not self.errors:
|
||||
@@ -361,9 +361,9 @@ class WorkerThread(QtCore.QThread):
|
||||
if not self.conversionAlive:
|
||||
for item in outputPath:
|
||||
if os.path.exists(item):
|
||||
saferRemove(item)
|
||||
os.remove(item)
|
||||
if os.path.exists(item.replace('.epub', '.mobi')):
|
||||
saferRemove(item.replace('.epub', '.mobi'))
|
||||
os.remove(item.replace('.epub', '.mobi'))
|
||||
self.clean()
|
||||
return
|
||||
if self.kindlegenErrorCode[0] == 0:
|
||||
@@ -384,7 +384,7 @@ class WorkerThread(QtCore.QThread):
|
||||
for item in outputPath:
|
||||
GUI.progress.content = ''
|
||||
mobiPath = item.replace('.epub', '.mobi')
|
||||
saferRemove(mobiPath + '_toclean')
|
||||
os.remove(mobiPath + '_toclean')
|
||||
if GUI.targetDirectory and GUI.targetDirectory != os.path.dirname(mobiPath):
|
||||
try:
|
||||
move(mobiPath, GUI.targetDirectory)
|
||||
@@ -402,9 +402,9 @@ class WorkerThread(QtCore.QThread):
|
||||
for item in outputPath:
|
||||
mobiPath = item.replace('.epub', '.mobi')
|
||||
if os.path.exists(mobiPath):
|
||||
saferRemove(mobiPath)
|
||||
os.remove(mobiPath)
|
||||
if os.path.exists(mobiPath + '_toclean'):
|
||||
saferRemove(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:
|
||||
@@ -412,9 +412,9 @@ class WorkerThread(QtCore.QThread):
|
||||
epubSize = (os.path.getsize(self.kindlegenErrorCode[2])) // 1024 // 1024
|
||||
for item in outputPath:
|
||||
if os.path.exists(item):
|
||||
saferRemove(item)
|
||||
os.remove(item)
|
||||
if os.path.exists(item.replace('.epub', '.mobi')):
|
||||
saferRemove(item.replace('.epub', '.mobi'))
|
||||
os.remove(item.replace('.epub', '.mobi'))
|
||||
MW.addMessage.emit('KindleGen failed to create MOBI!', 'error', False)
|
||||
MW.addTrayMessage.emit('KindleGen failed to create MOBI!', 'Critical')
|
||||
if self.kindlegenErrorCode[0] == 1 and self.kindlegenErrorCode[1] != '':
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
__version__ = '5.3.0'
|
||||
__version__ = '5.3.1'
|
||||
__license__ = 'ISC'
|
||||
__copyright__ = '2012-2017, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
@@ -22,12 +22,8 @@ from zipfile import is_zipfile, ZipFile
|
||||
from subprocess import STDOUT, PIPE
|
||||
from psutil import Popen
|
||||
from shutil import move, copy
|
||||
try:
|
||||
from scandir import walk
|
||||
except ImportError:
|
||||
walk = os.walk
|
||||
from . import rarfile
|
||||
from .shared import check7ZFile as is_7zfile, saferReplace, saferRemove
|
||||
from .shared import check7ZFile as is_7zfile
|
||||
|
||||
|
||||
class CBxArchive:
|
||||
@@ -50,12 +46,12 @@ class CBxArchive:
|
||||
filelist = []
|
||||
for f in cbzFile.namelist():
|
||||
if f.startswith('__MACOSX') or f.endswith('.DS_Store') or f.endswith('humbs.db'):
|
||||
pass # skip MacOS special files
|
||||
pass
|
||||
elif f.endswith('/'):
|
||||
try:
|
||||
os.makedirs(os.path.join(targetdir, f))
|
||||
except Exception:
|
||||
pass # the dir exists so we are going to extract the images only.
|
||||
pass
|
||||
else:
|
||||
filelist.append(f)
|
||||
cbzFile.extractall(targetdir, filelist)
|
||||
@@ -63,24 +59,18 @@ class CBxArchive:
|
||||
def extractCBR(self, targetdir):
|
||||
cbrFile = rarfile.RarFile(self.origFileName)
|
||||
cbrFile.extractall(targetdir)
|
||||
for root, dirnames, filenames in walk(targetdir):
|
||||
for root, _, filenames in os.walk(targetdir):
|
||||
for filename in filenames:
|
||||
if filename.startswith('__MACOSX') or filename.endswith('.DS_Store') or filename.endswith('humbs.db'):
|
||||
saferRemove(os.path.join(root, filename))
|
||||
os.remove(os.path.join(root, filename))
|
||||
|
||||
def extractCB7(self, targetdir):
|
||||
# Workaround for some wide UTF-8 + Popen abnormalities
|
||||
if sys.platform.startswith('darwin'):
|
||||
copy(self.origFileName, os.path.join(os.path.dirname(self.origFileName), 'TMP_KCC_TMP'))
|
||||
self.origFileName = os.path.join(os.path.dirname(self.origFileName), 'TMP_KCC_TMP')
|
||||
output = Popen('7za x "' + self.origFileName + '" -xr!__MACOSX -xr!.DS_Store -xr!thumbs.db -xr!Thumbs.db -o"' +
|
||||
targetdir + '"', stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=True)
|
||||
extracted = False
|
||||
for line in output.stdout:
|
||||
if b"Everything is Ok" in line:
|
||||
extracted = True
|
||||
if sys.platform.startswith('darwin'):
|
||||
saferRemove(self.origFileName)
|
||||
if not extracted:
|
||||
raise OSError
|
||||
|
||||
@@ -96,10 +86,6 @@ class CBxArchive:
|
||||
adir.remove('ComicInfo.xml')
|
||||
if len(adir) == 1 and os.path.isdir(os.path.join(targetdir, adir[0])):
|
||||
for f in os.listdir(os.path.join(targetdir, adir[0])):
|
||||
# If directory names contain UTF-8 chars shutil.move can't clean up the mess alone
|
||||
if os.path.isdir(os.path.join(targetdir, f)):
|
||||
saferReplace(os.path.join(targetdir, adir[0], f), os.path.join(targetdir, adir[0], f + '-A'))
|
||||
f += '-A'
|
||||
move(os.path.join(targetdir, adir[0], f), targetdir)
|
||||
os.rmdir(os.path.join(targetdir, adir[0]))
|
||||
return targetdir
|
||||
|
||||
@@ -36,17 +36,13 @@ from uuid import uuid4
|
||||
from slugify import slugify as slugifyExt
|
||||
from PIL import Image
|
||||
from subprocess import STDOUT, PIPE
|
||||
from psutil import Popen, virtual_memory
|
||||
from psutil import Popen, virtual_memory, disk_usage
|
||||
from html import escape
|
||||
try:
|
||||
from PyQt5 import QtCore
|
||||
except ImportError:
|
||||
QtCore = None
|
||||
try:
|
||||
from scandir import walk
|
||||
except ImportError:
|
||||
walk = os.walk
|
||||
from .shared import md5Checksum, getImageFileName, walkSort, walkLevel, saferReplace, saferRemove, sanitizeTrace
|
||||
from .shared import md5Checksum, getImageFileName, walkSort, walkLevel, sanitizeTrace
|
||||
from . import comic2panel
|
||||
from . import image
|
||||
from . import cbxarchive
|
||||
@@ -85,11 +81,11 @@ def buildHTML(path, imgfile, imgfilepath):
|
||||
imgfilepath = md5Checksum(imgfilepath)
|
||||
filename = getImageFileName(imgfile)
|
||||
deviceres = options.profileData[1]
|
||||
if "Rotated" in options.imgIndex[imgfilepath]:
|
||||
if "Rotated" in options.imgMetadata[imgfilepath]:
|
||||
rotatedPage = True
|
||||
else:
|
||||
rotatedPage = False
|
||||
if "BlackFill" in options.imgIndex[imgfilepath]:
|
||||
if "BlackBackground" in options.imgMetadata[imgfilepath]:
|
||||
additionalStyle = 'background-color:#000000;'
|
||||
else:
|
||||
additionalStyle = 'background-color:#FFFFFF;'
|
||||
@@ -424,7 +420,7 @@ def buildEPUB(path, chapterNames, tomeNumber):
|
||||
"display: none;\n",
|
||||
"}\n"])
|
||||
f.close()
|
||||
for (dirpath, dirnames, filenames) in walk(os.path.join(path, 'OEBPS', 'Images')):
|
||||
for dirpath, dirnames, filenames in os.walk(os.path.join(path, 'OEBPS', 'Images')):
|
||||
chapter = False
|
||||
dirnames, filenames = walkSort(dirnames, filenames)
|
||||
for afile in filenames:
|
||||
@@ -461,11 +457,11 @@ def imgDirectoryProcessing(path):
|
||||
global workerPool, workerOutput
|
||||
workerPool = Pool()
|
||||
workerOutput = []
|
||||
options.imgIndex = {}
|
||||
options.imgPurgeIndex = []
|
||||
options.imgMetadata = {}
|
||||
options.imgOld = []
|
||||
work = []
|
||||
pagenumber = 0
|
||||
for (dirpath, dirnames, filenames) in walk(path):
|
||||
for dirpath, _, filenames in os.walk(path):
|
||||
for afile in filenames:
|
||||
pagenumber += 1
|
||||
work.append([afile, dirpath, options])
|
||||
@@ -482,9 +478,9 @@ def imgDirectoryProcessing(path):
|
||||
if len(workerOutput) > 0:
|
||||
rmtree(os.path.join(path, '..', '..'), True)
|
||||
raise RuntimeError("One of workers crashed. Cause: " + workerOutput[0][0], workerOutput[0][1])
|
||||
for file in options.imgPurgeIndex:
|
||||
for file in options.imgOld:
|
||||
if os.path.isfile(file):
|
||||
saferRemove(file)
|
||||
os.remove(file)
|
||||
else:
|
||||
rmtree(os.path.join(path, '..', '..'), True)
|
||||
raise UserWarning("Source directory is empty.")
|
||||
@@ -497,8 +493,8 @@ def imgFileProcessingTick(output):
|
||||
else:
|
||||
for page in output:
|
||||
if page is not None:
|
||||
options.imgIndex[page[0]] = page[1]
|
||||
options.imgPurgeIndex.append(page[2])
|
||||
options.imgMetadata[page[0]] = page[1]
|
||||
options.imgOld.append(page[2])
|
||||
if GUI:
|
||||
GUI.progressBarTick.emit('tick')
|
||||
if not GUI.conversionAlive:
|
||||
@@ -513,7 +509,7 @@ def imgFileProcessing(work):
|
||||
output = []
|
||||
workImg = image.ComicPageParser((dirpath, afile), opt)
|
||||
for i in workImg.payload:
|
||||
img = image.ComicPage(i[0], i[1], i[2], i[3], i[4], opt)
|
||||
img = image.ComicPage(opt, *i)
|
||||
if opt.cropping == 2 and not opt.webtoon:
|
||||
img.cropPageNumber(opt.croppingp)
|
||||
if opt.cropping > 0 and not opt.webtoon:
|
||||
@@ -530,6 +526,8 @@ def imgFileProcessing(work):
|
||||
|
||||
def getWorkFolder(afile):
|
||||
if os.path.isdir(afile):
|
||||
if disk_usage(gettempdir())[2] < getDirectorySize(afile) * 2.5:
|
||||
raise UserWarning("Not enough disk space to perform conversion.")
|
||||
workdir = mkdtemp('', 'KCC-')
|
||||
try:
|
||||
os.rmdir(workdir)
|
||||
@@ -540,24 +538,27 @@ def getWorkFolder(afile):
|
||||
except:
|
||||
rmtree(workdir, True)
|
||||
raise UserWarning("Failed to prepare a workspace.")
|
||||
elif os.path.isfile(afile) and afile.lower().endswith('.pdf'):
|
||||
pdf = pdfjpgextract.PdfJpgExtract(afile)
|
||||
path, njpg = pdf.extract()
|
||||
if njpg == 0:
|
||||
rmtree(path, True)
|
||||
raise UserWarning("Failed to extract images from PDF file.")
|
||||
elif os.path.isfile(afile):
|
||||
workdir = mkdtemp('', 'KCC-')
|
||||
cbx = cbxarchive.CBxArchive(afile)
|
||||
if cbx.isCbxFile():
|
||||
try:
|
||||
path = cbx.extract(workdir)
|
||||
except:
|
||||
rmtree(workdir, True)
|
||||
raise UserWarning("Failed to extract archive.")
|
||||
if disk_usage(gettempdir())[2] < os.path.getsize(afile) * 2.5:
|
||||
raise UserWarning("Not enough disk space to perform conversion.")
|
||||
if afile.lower().endswith('.pdf'):
|
||||
pdf = pdfjpgextract.PdfJpgExtract(afile)
|
||||
path, njpg = pdf.extract()
|
||||
if njpg == 0:
|
||||
rmtree(path, True)
|
||||
raise UserWarning("Failed to extract images from PDF file.")
|
||||
else:
|
||||
rmtree(workdir, True)
|
||||
raise UserWarning("Failed to detect archive format.")
|
||||
workdir = mkdtemp('', 'KCC-')
|
||||
cbx = cbxarchive.CBxArchive(afile)
|
||||
if cbx.isCbxFile():
|
||||
try:
|
||||
path = cbx.extract(workdir)
|
||||
except:
|
||||
rmtree(workdir, True)
|
||||
raise UserWarning("Failed to extract archive.")
|
||||
else:
|
||||
rmtree(workdir, True)
|
||||
raise UserWarning("Failed to detect archive format.")
|
||||
else:
|
||||
raise UserWarning("Failed to open source file/directory.")
|
||||
sanitizePermissions(path)
|
||||
@@ -619,7 +620,7 @@ def getComicInfo(path, originalPath):
|
||||
try:
|
||||
xml = metadata.MetadataParser(xmlPath)
|
||||
except Exception:
|
||||
saferRemove(xmlPath)
|
||||
os.remove(xmlPath)
|
||||
return
|
||||
options.authors = []
|
||||
if defaultTitle:
|
||||
@@ -644,7 +645,7 @@ def getComicInfo(path, originalPath):
|
||||
options.chapters = xml.data['Bookmarks']
|
||||
if xml.data['Summary']:
|
||||
options.summary = escape(xml.data['Summary'])
|
||||
saferRemove(xmlPath)
|
||||
os.remove(xmlPath)
|
||||
|
||||
|
||||
def getCoversFromMCB(mangaID):
|
||||
@@ -663,7 +664,7 @@ def getCoversFromMCB(mangaID):
|
||||
|
||||
def getDirectorySize(start_path='.'):
|
||||
total_size = 0
|
||||
for dirpath, dirnames, filenames in walk(start_path):
|
||||
for dirpath, _, filenames in os.walk(start_path):
|
||||
for f in filenames:
|
||||
fp = os.path.join(dirpath, f)
|
||||
total_size += os.path.getsize(fp)
|
||||
@@ -688,7 +689,7 @@ def getPanelViewSize(deviceres, size):
|
||||
|
||||
def sanitizeTree(filetree):
|
||||
chapterNames = {}
|
||||
for root, dirs, files in walk(filetree, False):
|
||||
for root, dirs, files in os.walk(filetree, False):
|
||||
for name in files:
|
||||
splitname = os.path.splitext(name)
|
||||
slugified = slugify(splitname[0])
|
||||
@@ -698,7 +699,7 @@ def sanitizeTree(filetree):
|
||||
newKey = os.path.join(root, slugified + splitname[1])
|
||||
key = os.path.join(root, name)
|
||||
if key != newKey:
|
||||
saferReplace(key, newKey)
|
||||
os.replace(key, newKey)
|
||||
for name in dirs:
|
||||
tmpName = name
|
||||
slugified = slugify(name)
|
||||
@@ -708,13 +709,13 @@ def sanitizeTree(filetree):
|
||||
newKey = os.path.join(root, slugified)
|
||||
key = os.path.join(root, name)
|
||||
if key != newKey:
|
||||
saferReplace(key, newKey)
|
||||
os.replace(key, newKey)
|
||||
return chapterNames
|
||||
|
||||
|
||||
def sanitizeTreeKobo(filetree):
|
||||
pageNumber = 0
|
||||
for root, dirs, files in walk(filetree):
|
||||
for root, dirs, files in os.walk(filetree):
|
||||
dirs, files = walkSort(dirs, files)
|
||||
for name in files:
|
||||
splitname = os.path.splitext(name)
|
||||
@@ -726,11 +727,11 @@ def sanitizeTreeKobo(filetree):
|
||||
newKey = os.path.join(root, slugified + splitname[1])
|
||||
key = os.path.join(root, name)
|
||||
if key != newKey:
|
||||
saferReplace(key, newKey)
|
||||
os.replace(key, newKey)
|
||||
|
||||
|
||||
def sanitizePermissions(filetree):
|
||||
for root, dirs, files in walk(filetree, False):
|
||||
for root, dirs, files in os.walk(filetree, False):
|
||||
for name in files:
|
||||
os.chmod(os.path.join(root, name), S_IWRITE | S_IREAD)
|
||||
for name in dirs:
|
||||
@@ -785,7 +786,7 @@ def splitProcess(path, mode):
|
||||
move(os.path.join(root, name), os.path.join(currentTarget, name))
|
||||
else:
|
||||
firstTome = True
|
||||
for root, dirs, files in walkLevel(path, 0):
|
||||
for root, dirs, _ in walkLevel(path, 0):
|
||||
for name in dirs:
|
||||
if not firstTome:
|
||||
currentTarget, pathRoot = createNewTome()
|
||||
@@ -799,9 +800,12 @@ def splitProcess(path, mode):
|
||||
def detectCorruption(tmpPath, orgPath):
|
||||
imageNumber = 0
|
||||
imageSmaller = 0
|
||||
for root, dirs, files in walk(tmpPath, False):
|
||||
alreadyProcessed = False
|
||||
for root, _, files in os.walk(tmpPath, False):
|
||||
for name in files:
|
||||
if getImageFileName(name) is not None:
|
||||
if not alreadyProcessed and getImageFileName(name)[0].endswith('-kcc'):
|
||||
alreadyProcessed = True
|
||||
path = os.path.join(root, name)
|
||||
pathOrg = orgPath + path.split('OEBPS' + os.path.sep + 'Images')[1]
|
||||
if os.path.getsize(path) == 0:
|
||||
@@ -822,7 +826,13 @@ def detectCorruption(tmpPath, orgPath):
|
||||
else:
|
||||
raise RuntimeError('Image file %s is corrupted.' % pathOrg)
|
||||
else:
|
||||
saferRemove(os.path.join(root, name))
|
||||
os.remove(os.path.join(root, name))
|
||||
if alreadyProcessed:
|
||||
print("WARNING: Source files are probably created by KCC. Second conversion will decrease quality.")
|
||||
if GUI:
|
||||
GUI.addMessage.emit('Source files are probably created by KCC. Second conversion will decrease quality.',
|
||||
'warning', False)
|
||||
GUI.addMessage.emit('', '', False)
|
||||
if imageSmaller > imageNumber * 0.25 and not options.upscale and not options.stretch:
|
||||
print("WARNING: More than 25% of images are smaller than target device resolution. "
|
||||
"Consider enabling stretching or upscaling to improve readability.")
|
||||
@@ -850,7 +860,7 @@ def makeZIP(zipFilename, baseDir, isEPUB=False):
|
||||
zipOutput = ZipFile(zipFilename, 'w', ZIP_DEFLATED)
|
||||
if isEPUB:
|
||||
zipOutput.writestr('mimetype', 'application/epub+zip', ZIP_STORED)
|
||||
for dirpath, dirnames, filenames in walk(baseDir):
|
||||
for dirpath, _, filenames in os.walk(baseDir):
|
||||
for name in filenames:
|
||||
path = os.path.normpath(os.path.join(dirpath, name))
|
||||
aPath = os.path.normpath(os.path.join(dirpath.replace(baseDir, ''), name))
|
||||
@@ -1107,14 +1117,14 @@ def makeBook(source, qtGUI=None):
|
||||
print('Error: Failed to tweak KindleGen output!')
|
||||
return filepath
|
||||
else:
|
||||
saferRemove(i.replace('.epub', '.mobi') + '_toclean')
|
||||
os.remove(i.replace('.epub', '.mobi') + '_toclean')
|
||||
if k.path and k.coverSupport:
|
||||
options.covers[filepath.index(i)][0].saveToKindle(k, options.covers[filepath.index(i)][1])
|
||||
return filepath
|
||||
|
||||
|
||||
def makeMOBIFix(item, uuid):
|
||||
saferRemove(item)
|
||||
os.remove(item)
|
||||
mobiPath = item.replace('.epub', '.mobi')
|
||||
move(mobiPath, mobiPath + '_toclean')
|
||||
try:
|
||||
|
||||
@@ -24,15 +24,11 @@ from shutil import rmtree, copytree, move
|
||||
from optparse import OptionParser, OptionGroup
|
||||
from multiprocessing import Pool
|
||||
from PIL import Image, ImageStat, ImageOps
|
||||
from .shared import getImageFileName, walkLevel, walkSort, saferRemove, sanitizeTrace
|
||||
from .shared import getImageFileName, walkLevel, walkSort, sanitizeTrace
|
||||
try:
|
||||
from PyQt5 import QtCore
|
||||
except ImportError:
|
||||
QtCore = None
|
||||
try:
|
||||
from scandir import walk
|
||||
except ImportError:
|
||||
walk = os.walk
|
||||
|
||||
|
||||
def mergeDirectoryTick(output):
|
||||
@@ -52,7 +48,7 @@ def mergeDirectory(work):
|
||||
imagesValid = []
|
||||
sizes = []
|
||||
targetHeight = 0
|
||||
for root, dirs, files in walkLevel(directory, 0):
|
||||
for root, _, files in walkLevel(directory, 0):
|
||||
for name in files:
|
||||
if getImageFileName(name) is not None:
|
||||
i = Image.open(os.path.join(root, name))
|
||||
@@ -77,7 +73,7 @@ def mergeDirectory(work):
|
||||
img = ImageOps.fit(img, (targetWidth, img.size[1]), method=Image.BICUBIC, centering=(0.5, 0.5))
|
||||
result.paste(img, (0, y))
|
||||
y += img.size[1]
|
||||
saferRemove(i)
|
||||
os.remove(i)
|
||||
savePath = os.path.split(imagesValid[0])
|
||||
result.save(os.path.join(savePath[0], os.path.splitext(savePath[1])[0] + '.png'), 'PNG')
|
||||
except Exception:
|
||||
@@ -203,7 +199,7 @@ def splitImage(work):
|
||||
targetHeight += panels[panel][2]
|
||||
newPage.save(os.path.join(path, fileExpanded[0] + '-' + str(pageNumber) + '.png'), 'PNG')
|
||||
pageNumber += 1
|
||||
saferRemove(filePath)
|
||||
os.remove(filePath)
|
||||
except Exception:
|
||||
return str(sys.exc_info()[1]), sanitizeTrace(sys.exc_info()[2])
|
||||
|
||||
@@ -250,7 +246,7 @@ def main(argv=None, qtGUI=None):
|
||||
mergeWorkerOutput = []
|
||||
mergeWorkerPool = Pool()
|
||||
mergeWork.append([options.targetDir])
|
||||
for root, dirs, files in walk(options.targetDir, False):
|
||||
for root, dirs, files in os.walk(options.targetDir, False):
|
||||
dirs, files = walkSort(dirs, files)
|
||||
for directory in dirs:
|
||||
directoryNumer += 1
|
||||
@@ -269,13 +265,13 @@ def main(argv=None, qtGUI=None):
|
||||
rmtree(options.targetDir, True)
|
||||
raise RuntimeError("One of workers crashed. Cause: " + mergeWorkerOutput[0][0], mergeWorkerOutput[0][1])
|
||||
print("Splitting images...")
|
||||
for root, dirs, files in walk(options.targetDir, False):
|
||||
for root, _, files in os.walk(options.targetDir, False):
|
||||
for name in files:
|
||||
if getImageFileName(name) is not None:
|
||||
pagenumber += 1
|
||||
work.append([root, name, options])
|
||||
else:
|
||||
saferRemove(os.path.join(root, name))
|
||||
os.remove(os.path.join(root, name))
|
||||
if GUI:
|
||||
GUI.progressBarTick.emit('Splitting images')
|
||||
GUI.progressBarTick.emit(str(pagenumber))
|
||||
|
||||
@@ -206,7 +206,7 @@ class ComicPageParser:
|
||||
|
||||
|
||||
class ComicPage:
|
||||
def __init__(self, mode, path, image, color, fill, options):
|
||||
def __init__(self, options, mode, path, image, color, fill):
|
||||
self.opt = options
|
||||
_, self.size, self.palette, self.gamma = self.opt.profileData
|
||||
self.image = image
|
||||
@@ -232,16 +232,16 @@ class ComicPage:
|
||||
if self.rotated:
|
||||
flags.append('Rotated')
|
||||
if self.fill != 'white':
|
||||
flags.append('BlackFill')
|
||||
flags.append('BlackBackground')
|
||||
if self.opt.forcepng:
|
||||
self.targetPath += '.png'
|
||||
self.image.save(self.targetPath, 'PNG', optimize=1)
|
||||
else:
|
||||
self.targetPath += '.jpg'
|
||||
self.image.save(self.targetPath, 'JPEG', optimize=1, quality=80)
|
||||
self.image.save(self.targetPath, 'JPEG', optimize=1, quality=85)
|
||||
return [md5Checksum(self.targetPath), flags, self.orgPath]
|
||||
except IOError:
|
||||
raise RuntimeError('Cannot save image.')
|
||||
except IOError as err:
|
||||
raise RuntimeError('Cannot save image. ' + str(err))
|
||||
|
||||
def autocontrastImage(self):
|
||||
gamma = self.opt.gamma
|
||||
@@ -361,7 +361,7 @@ class Cover:
|
||||
|
||||
def save(self):
|
||||
try:
|
||||
self.image.save(self.target, "JPEG", optimize=1, quality=80)
|
||||
self.image.save(self.target, "JPEG", optimize=1, quality=85)
|
||||
except IOError:
|
||||
raise RuntimeError('Failed to process downloaded cover.')
|
||||
|
||||
@@ -369,6 +369,6 @@ class Cover:
|
||||
self.image = self.image.resize((300, 470), Image.ANTIALIAS)
|
||||
try:
|
||||
self.image.save(os.path.join(kindle.path.split('documents')[0], 'system', 'thumbnails',
|
||||
'thumbnail_' + asin + '_EBOK_portrait.jpg'), 'JPEG')
|
||||
'thumbnail_' + asin + '_EBOK_portrait.jpg'), 'JPEG', optimize=1, quality=85)
|
||||
except IOError:
|
||||
raise RuntimeError('Failed to upload cover.')
|
||||
|
||||
@@ -27,10 +27,6 @@ from tempfile import mkdtemp
|
||||
from zipfile import ZipFile, ZIP_DEFLATED
|
||||
from re import split
|
||||
from traceback import format_tb
|
||||
try:
|
||||
from scandir import walk
|
||||
except ImportError:
|
||||
walk = os.walk
|
||||
|
||||
|
||||
class HTMLStripper(HTMLParser):
|
||||
@@ -71,7 +67,7 @@ def walkLevel(some_dir, level=1):
|
||||
some_dir = some_dir.rstrip(os.path.sep)
|
||||
assert os.path.isdir(some_dir)
|
||||
num_sep = some_dir.count(os.path.sep)
|
||||
for root, dirs, files in walk(some_dir):
|
||||
for root, dirs, files in os.walk(some_dir):
|
||||
dirs, files = walkSort(dirs, files)
|
||||
yield root, dirs, files
|
||||
num_sep_this = root.count(os.path.sep)
|
||||
@@ -96,30 +92,6 @@ def check7ZFile(filePath):
|
||||
return header == b"7z\xbc\xaf'\x1c"
|
||||
|
||||
|
||||
def saferReplace(old, new):
|
||||
for x in range(30):
|
||||
try:
|
||||
os.replace(old, new)
|
||||
except PermissionError:
|
||||
sleep(1)
|
||||
else:
|
||||
break
|
||||
else:
|
||||
raise PermissionError("Failed to move the file.")
|
||||
|
||||
|
||||
def saferRemove(target):
|
||||
for x in range(30):
|
||||
try:
|
||||
os.remove(target)
|
||||
except PermissionError:
|
||||
sleep(1)
|
||||
else:
|
||||
break
|
||||
else:
|
||||
raise PermissionError("Failed to remove the file.")
|
||||
|
||||
|
||||
def removeFromZIP(zipfname, *filenames):
|
||||
tempdir = mkdtemp('', 'KCC-')
|
||||
try:
|
||||
@@ -129,15 +101,7 @@ def removeFromZIP(zipfname, *filenames):
|
||||
for item in zipread.infolist():
|
||||
if item.filename not in filenames:
|
||||
zipwrite.writestr(item, zipread.read(item.filename))
|
||||
for x in range(30):
|
||||
try:
|
||||
copy(tempname, zipfname)
|
||||
except PermissionError:
|
||||
sleep(1)
|
||||
else:
|
||||
break
|
||||
else:
|
||||
raise PermissionError
|
||||
copy(tempname, zipfname)
|
||||
finally:
|
||||
rmtree(tempdir, True)
|
||||
|
||||
@@ -164,33 +128,26 @@ def dependencyCheck(level):
|
||||
try:
|
||||
import raven
|
||||
except ImportError:
|
||||
missing.append('raven 5.13.0+')
|
||||
missing.append('raven 6.0.0+')
|
||||
if level > 1:
|
||||
try:
|
||||
from psutil import __version__ as psutilVersion
|
||||
if StrictVersion('4.1.0') > StrictVersion(psutilVersion):
|
||||
missing.append('psutil 4.1.0+')
|
||||
if StrictVersion('5.0.0') > StrictVersion(psutilVersion):
|
||||
missing.append('psutil 5.0.0+')
|
||||
except ImportError:
|
||||
missing.append('psutil 4.1.0+')
|
||||
missing.append('psutil 5.0.0+')
|
||||
try:
|
||||
from slugify import __version__ as slugifyVersion
|
||||
if StrictVersion('1.2.0') > StrictVersion(slugifyVersion):
|
||||
missing.append('python-slugify 1.2.0+')
|
||||
if StrictVersion('1.2.1') > StrictVersion(slugifyVersion):
|
||||
missing.append('python-slugify 1.2.1+')
|
||||
except ImportError:
|
||||
missing.append('python-slugify 1.2.0+')
|
||||
missing.append('python-slugify 1.2.1+')
|
||||
try:
|
||||
from PIL import PILLOW_VERSION as pillowVersion
|
||||
if StrictVersion('3.2.0') > StrictVersion(pillowVersion):
|
||||
missing.append('Pillow 3.2.0+')
|
||||
if StrictVersion('4.0.0') > StrictVersion(pillowVersion):
|
||||
missing.append('Pillow 4.0.0+')
|
||||
except ImportError:
|
||||
missing.append('Pillow 3.2.0+')
|
||||
if version_info[1] < 5:
|
||||
try:
|
||||
from scandir import __version__ as scandirVersion
|
||||
if StrictVersion('1.2') > StrictVersion(scandirVersion):
|
||||
missing.append('scandir 1.2+')
|
||||
except ImportError:
|
||||
missing.append('scandir 1.2+')
|
||||
missing.append('Pillow 4.0.0+')
|
||||
if len(missing) > 0:
|
||||
print('ERROR: ' + ', '.join(missing) + ' is not installed!')
|
||||
exit(1)
|
||||
|
||||
53
kindlecomicconverter/startup.py
Normal file
53
kindlecomicconverter/startup.py
Normal file
@@ -0,0 +1,53 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
||||
# Copyright (c) 2013-2017 Pawel Jastrzebski <pawelj@iosphe.re>
|
||||
#
|
||||
# Permission to use, copy, modify, and/or distribute this software for
|
||||
# any purpose with or without fee is hereby granted, provided that the
|
||||
# above copyright notice and this permission notice appear in all
|
||||
# copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||
# WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
||||
# AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
# DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
|
||||
# OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
# PERFORMANCE OF THIS SOFTWARE.
|
||||
#
|
||||
|
||||
import os
|
||||
import sys
|
||||
from . import __version__
|
||||
from .shared import dependencyCheck
|
||||
|
||||
def start():
|
||||
dependencyCheck(3)
|
||||
from . import KCC_gui
|
||||
os.environ['QT_AUTO_SCREEN_SCALE_FACTOR'] = "1"
|
||||
KCCAplication = KCC_gui.QApplicationMessaging(sys.argv)
|
||||
if KCCAplication.isRunning():
|
||||
if len(sys.argv) > 1:
|
||||
KCCAplication.sendMessage(sys.argv[1])
|
||||
else:
|
||||
KCCAplication.sendMessage('ARISE')
|
||||
else:
|
||||
KCCWindow = KCC_gui.QMainWindowKCC()
|
||||
KCCUI = KCC_gui.KCCGUI(KCCAplication, KCCWindow)
|
||||
if len(sys.argv) > 1:
|
||||
KCCUI.handleMessage(sys.argv[1])
|
||||
sys.exit(KCCAplication.exec_())
|
||||
|
||||
def startC2E():
|
||||
dependencyCheck(2)
|
||||
from .comic2ebook import main
|
||||
print('comic2ebook v' + __version__ + ' - Written by Ciro Mattia Gonano and Pawel Jastrzebski.')
|
||||
sys.exit(main(sys.argv[1:]))
|
||||
|
||||
def startC2P():
|
||||
dependencyCheck(1)
|
||||
from .comic2panel import main
|
||||
print('comic2panel v' + __version__ + ' - Written by Ciro Mattia Gonano and Pawel Jastrzebski.')
|
||||
sys.exit(main(sys.argv[1:]))
|
||||
@@ -30,7 +30,7 @@
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>MacOS/Kindle Comic Converter</string>
|
||||
<key>CFBundleGetInfoString</key>
|
||||
<string>KindleComicConverter 5.3.0, written 2012-2017 by Ciro Mattia Gonano and Pawel Jastrzebski</string>
|
||||
<string>KindleComicConverter 5.3.1, written 2012-2017 by Ciro Mattia Gonano and Pawel Jastrzebski</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>comic2ebook.icns</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
@@ -42,11 +42,11 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>5.3.0</string>
|
||||
<string>5.3.1</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>5.3.0</string>
|
||||
<string>5.3.1</string>
|
||||
<key>LSEnvironment</key>
|
||||
<dict>
|
||||
<key>PATH</key>
|
||||
|
||||
5
requirements.txt
Normal file
5
requirements.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
PyQt5>=5.6.0
|
||||
Pillow>=4.0.0
|
||||
psutil>=5.0.0
|
||||
python-slugify>=1.2.1
|
||||
raven>=6.0.0
|
||||
92
setup.py
92
setup.py
@@ -6,7 +6,7 @@ Usage (Windows):
|
||||
py -3 setup.py build_binary
|
||||
|
||||
Usage (Linux/OS X):
|
||||
python3 setup.py build_binary or python3 setup.py build_binary --pyz
|
||||
python3 setup.py build_binary
|
||||
"""
|
||||
|
||||
import os
|
||||
@@ -20,8 +20,6 @@ from kindlecomicconverter import __version__
|
||||
NAME = 'KindleComicConverter'
|
||||
MAIN = 'kcc.py'
|
||||
VERSION = __version__
|
||||
OPTIONS = {}
|
||||
|
||||
|
||||
class BuildBinaryCommand(distutils.cmd.Command):
|
||||
description = 'build binary release'
|
||||
@@ -62,74 +60,12 @@ class BuildBinaryCommand(distutils.cmd.Command):
|
||||
os.system('setup.bat')
|
||||
exit(0)
|
||||
else:
|
||||
if self.pyz:
|
||||
script = '''
|
||||
cp kcc.py __main__.py
|
||||
zip kcc.zip __main__.py kindlecomicconverter/*.py
|
||||
echo "#!/usr/bin/env python3" > kcc-bin
|
||||
cat kcc.zip >> kcc-bin
|
||||
chmod +x kcc-bin
|
||||
|
||||
cp kcc-c2e.py __main__.py
|
||||
zip kcc-c2e.zip __main__.py kindlecomicconverter/*.py
|
||||
echo "#!/usr/bin/env python3" > kcc-c2e-bin
|
||||
cat kcc-c2e.zip >> kcc-c2e-bin
|
||||
chmod +x kcc-c2e-bin
|
||||
|
||||
cp kcc-c2p.py __main__.py
|
||||
zip kcc-c2p.zip __main__.py kindlecomicconverter/*.py
|
||||
echo "#!/usr/bin/env python3" > kcc-c2p-bin
|
||||
cat kcc-c2p.zip >> kcc-c2p-bin
|
||||
chmod +x kcc-c2p-bin
|
||||
|
||||
mkdir dist
|
||||
tar --xform s:^.*/:: \
|
||||
--xform s/LICENSE.txt/LICENSE/ \
|
||||
--xform s/kcc-bin/kcc/ \
|
||||
--xform s/kcc-c2p-bin/kcc-c2p/ \
|
||||
--xform s/kcc-c2e-bin/kcc-c2e/ \
|
||||
--xform s/comic2ebook/kcc/ \
|
||||
-czf dist/KindleComicConverter_linux_''' + VERSION + '''.tar.gz \
|
||||
kcc-bin kcc-c2e-bin kcc-c2p-bin LICENSE.txt README.md icons/comic2ebook.png
|
||||
rm __main__.py kcc.zip kcc-c2e.zip kcc-c2p.zip kcc-bin kcc-c2e-bin kcc-c2p-bin
|
||||
'''
|
||||
os.system("bash -c '%s'" % script)
|
||||
exit(0)
|
||||
else:
|
||||
os.system('docker run --rm -v ' + os.getcwd() + ':/app -e KCCVER=' + VERSION + ' acidweb/kcc')
|
||||
exit(0)
|
||||
|
||||
|
||||
class BuildCommand(build):
|
||||
def run(self):
|
||||
os.makedirs('build/_scripts/', exist_ok=True)
|
||||
shutil.copyfile('kcc.py', 'build/_scripts/kcc')
|
||||
shutil.copyfile('kcc-c2e.py', 'build/_scripts/kcc-c2e')
|
||||
shutil.copyfile('kcc-c2p.py', 'build/_scripts/kcc-c2p')
|
||||
# noinspection PyShadowingNames
|
||||
OPTIONS = dict(
|
||||
scripts=['build/_scripts/kcc',
|
||||
'build/_scripts/kcc-c2e',
|
||||
'build/_scripts/kcc-c2p'],
|
||||
packages=['kcc'],
|
||||
install_requires=[
|
||||
'PyQt5>=5.6.0'
|
||||
'Pillow>=3.2.0',
|
||||
'psutil>=4.1.0',
|
||||
'python-slugify>=1.2.0',
|
||||
'raven>=5.13.0',
|
||||
],
|
||||
zip_safe=False,
|
||||
)
|
||||
if sys.version_info[1] < 5:
|
||||
OPTIONS['install_requires'].append('scandir>=1.2.0')
|
||||
build.run(self)
|
||||
|
||||
os.system('docker run --rm -v ' + os.getcwd() + ':/app -e KCCVER=' + VERSION + ' acidweb/kcc')
|
||||
exit(0)
|
||||
|
||||
setuptools.setup(
|
||||
cmdclass={
|
||||
'build_binary': BuildBinaryCommand,
|
||||
'build': BuildCommand,
|
||||
},
|
||||
name=NAME,
|
||||
version=VERSION,
|
||||
@@ -137,7 +73,25 @@ setuptools.setup(
|
||||
author_email='ciromattia@gmail.com, pawelj@iosphe.re',
|
||||
description='Comic and Manga converter for e-book readers.',
|
||||
license='ISC License (ISCL)',
|
||||
keywords='kindle comic mobipocket mobi cbz cbr manga',
|
||||
keywords=['kindle', 'kobo', 'comic', 'manga', 'mobi', 'epub', 'cbz'],
|
||||
url='http://github.com/ciromattia/kcc',
|
||||
**OPTIONS
|
||||
entry_points={
|
||||
'console_scripts': [
|
||||
'kcc-c2e = kindlecomicconverter.startup:startC2E',
|
||||
'kcc-c2p = kindlecomicconverter.startup:startC2P',
|
||||
],
|
||||
'gui_scripts': [
|
||||
'kcc = kindlecomicconverter.startup:start',
|
||||
],
|
||||
},
|
||||
packages=['kindlecomicconverter'],
|
||||
install_requires=[
|
||||
'PyQt5>=5.6.0',
|
||||
'Pillow>=4.0.0',
|
||||
'psutil>=5.0.0',
|
||||
'python-slugify>=1.2.1',
|
||||
'raven>=6.0.0',
|
||||
],
|
||||
classifiers = [],
|
||||
zip_safe=False,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user