mirror of
https://github.com/ciromattia/kcc
synced 2025-12-13 17:56:30 +00:00
53
README.md
53
README.md
@@ -1,13 +1,13 @@
|
|||||||
# KCC
|
# KCC
|
||||||
|
|
||||||
**Kindle Comic Converter** is a Python app to convert comic files or folders to ePub, Panel View MOBI or E-Ink optimized CBZ.
|
**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 initally developed for Kindle but since v2.2 it outputs valid ePub 2.0 so _**despite its name, KCC is
|
It was initially developed for Kindle but since version 2.2 it outputs valid EPUB 2.0 so _**despite its name, KCC is
|
||||||
actually a comic 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 readers.
|
Amazon's tool is for comic publishers and involves a lot of manual effort, while **KCC** is for comic/manga readers.
|
||||||
_KC2_ in no way is a replacement for **KCC** so you can be quite confident we'll going to carry on developing our little monster ;-)
|
_KC2_ in no way is a replacement for **KCC** so you can be quite confident we'll going to carry on developing our little monster ;-)
|
||||||
|
|
||||||
### Issues / new features / donations
|
### Issues / new features / donations
|
||||||
@@ -36,7 +36,7 @@ You can find the latest released binary at the following links:
|
|||||||
- CBZ, ZIP
|
- CBZ, ZIP
|
||||||
- CBR, RAR *(With `unrar` executable)*
|
- CBR, RAR *(With `unrar` executable)*
|
||||||
- CB7, 7Z *(With `7za` executable)*
|
- CB7, 7Z *(With `7za` executable)*
|
||||||
- PDF *(Extracting only contained JPG images)*
|
- PDF *(Only extracting JPG images)*
|
||||||
|
|
||||||
## OPTIONAL REQUIREMENTS
|
## OPTIONAL REQUIREMENTS
|
||||||
- [KindleGen](http://www.amazon.com/gp/feature.html?ie=UTF8&docId=1000765211) v2.9+ in a directory reachable by your _PATH_ or in _KCC_ directory *(For MOBI generation)*
|
- [KindleGen](http://www.amazon.com/gp/feature.html?ie=UTF8&docId=1000765211) v2.9+ in a directory reachable by your _PATH_ or in _KCC_ directory *(For MOBI generation)*
|
||||||
@@ -67,6 +67,8 @@ After completed conversion you should find ready file alongside the original inp
|
|||||||
|
|
||||||
Please check [our wiki](https://github.com/ciromattia/kcc/wiki/) for more details.
|
Please check [our wiki](https://github.com/ciromattia/kcc/wiki/) for more details.
|
||||||
|
|
||||||
|
CLI version of **KCC** is intended for power users. It is not idiot-proof like GUI :-)
|
||||||
|
|
||||||
### Standalone `kcc-c2e.py` usage:
|
### Standalone `kcc-c2e.py` usage:
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -75,7 +77,9 @@ Usage: kcc-c2e [options] comic_file|comic_folder
|
|||||||
Options:
|
Options:
|
||||||
MAIN:
|
MAIN:
|
||||||
-p PROFILE, --profile=PROFILE
|
-p PROFILE, --profile=PROFILE
|
||||||
Device profile (Choose one among K1, K2, K345, KDX, KHD, KF, KFHD, KFHD8, KFHDX, KFHDX8, KFA, KoMT, KoG, KoA, KoAHD) [Default=KHD]
|
Device profile (Available options: K1, K2, K345, KDX,
|
||||||
|
KPW, KV, KFHD, KFHDX, KFHDX8, KFA, KoMT, KoG, KoA,
|
||||||
|
KoAHD, KoAH2O) [Default=KV]
|
||||||
-q QUALITY, --quality=QUALITY
|
-q QUALITY, --quality=QUALITY
|
||||||
Quality of Panel View. 0 - Normal 1 - High 2 - Ultra [Default=0]
|
Quality of Panel View. 0 - Normal 1 - High 2 - Ultra [Default=0]
|
||||||
-m, --manga-style Manga style (Right-to-left reading and splitting)
|
-m, --manga-style Manga style (Right-to-left reading and splitting)
|
||||||
@@ -86,7 +90,9 @@ Options:
|
|||||||
Output generated file to specified directory or file
|
Output generated file to specified directory or file
|
||||||
-t TITLE, --title=TITLE
|
-t TITLE, --title=TITLE
|
||||||
Comic title [Default=filename or directory name]
|
Comic title [Default=filename or directory name]
|
||||||
--cbz-output Outputs a CBZ archive and does not generate EPUB
|
-f FORMAT, --format=FORMAT
|
||||||
|
Output format (Available options: Auto, MOBI,
|
||||||
|
EPUB, CBZ) [Default=Auto]
|
||||||
--batchsplit Split output into multiple files
|
--batchsplit Split output into multiple files
|
||||||
|
|
||||||
PROCESSING:
|
PROCESSING:
|
||||||
@@ -134,7 +140,7 @@ Options:
|
|||||||
|
|
||||||
This script born as a cross-platform alternative to `KindleComicParser` by **Dc5e** (published [here](http://www.mobileread.com/forums/showthread.php?t=192783)).
|
This script born as a cross-platform alternative to `KindleComicParser` by **Dc5e** (published [here](http://www.mobileread.com/forums/showthread.php?t=192783)).
|
||||||
|
|
||||||
The app relies and includes the following scripts/binaries:
|
The app relies and includes the following scripts:
|
||||||
|
|
||||||
- `DualMetaFix` script by **K. Hendricks**. Released with GPL-3 License.
|
- `DualMetaFix` script by **K. Hendricks**. Released with GPL-3 License.
|
||||||
- `rarfile.py` script © 2005-2011 **Marko Kreen** <markokr@gmail.com>. Released with ISC License.
|
- `rarfile.py` script © 2005-2011 **Marko Kreen** <markokr@gmail.com>. Released with ISC License.
|
||||||
@@ -142,17 +148,15 @@ The app relies and includes the following scripts/binaries:
|
|||||||
- Icon is by **Nikolay Verin** ([http://ncrow.deviantart.com/](http://ncrow.deviantart.com/)) and released under [CC BY-NC-SA 3.0](http://creativecommons.org/licenses/by-nc-sa/3.0/) License.
|
- Icon is by **Nikolay Verin** ([http://ncrow.deviantart.com/](http://ncrow.deviantart.com/)) and released under [CC BY-NC-SA 3.0](http://creativecommons.org/licenses/by-nc-sa/3.0/) License.
|
||||||
|
|
||||||
## SAMPLE FILES CREATED BY KCC
|
## SAMPLE FILES CREATED BY KCC
|
||||||
|
* [Kindle Voyage](http://kcc.iosphe.re/Samples/Ubunchu!-KV.mobi)
|
||||||
* [Kindle Paperwhite](http://kcc.iosphe.re/Samples/Ubunchu!-KPW.mobi)
|
* [Kindle Paperwhite](http://kcc.iosphe.re/Samples/Ubunchu!-KPW.mobi)
|
||||||
* [Kindle](http://kcc.iosphe.re/Samples/Ubunchu!-K345.mobi)
|
* [Kindle](http://kcc.iosphe.re/Samples/Ubunchu!-K345.mobi)
|
||||||
* [Kindle DX/DXG](http://kcc.iosphe.re/Samples/Ubunchu!-KDX.mobi)
|
* [Kindle DX/DXG](http://kcc.iosphe.re/Samples/Ubunchu!-KDX.cbz)
|
||||||
* [Kindle Fire HD](http://kcc.iosphe.re/Samples/Ubunchu!-KFHD.mobi)
|
|
||||||
* [Kindle Fire HD 8.9"](http://kcc.iosphe.re/Samples/Ubunchu!-KFHD8.mobi)
|
|
||||||
* [Kindle Fire HDX](http://kcc.iosphe.re/Samples/Ubunchu!-KFHDX.mobi)
|
|
||||||
* [Kindle Fire HDX 8.9"](http://kcc.iosphe.re/Samples/Ubunchu!-KFHDX8.mobi)
|
|
||||||
* [Kobo Mini/Touch](http://kcc.iosphe.re/Samples/Ubunchu!-KoMT.cbz)
|
* [Kobo Mini/Touch](http://kcc.iosphe.re/Samples/Ubunchu!-KoMT.cbz)
|
||||||
* [Kobo Glow](http://kcc.iosphe.re/Samples/Ubunchu!-KoG.cbz)
|
* [Kobo Glow](http://kcc.iosphe.re/Samples/Ubunchu!-KoG.cbz)
|
||||||
* [Kobo Aura](http://kcc.iosphe.re/Samples/Ubunchu!-KoA.cbz)
|
* [Kobo Aura](http://kcc.iosphe.re/Samples/Ubunchu!-KoA.cbz)
|
||||||
* [Kobo Aura HD](http://kcc.iosphe.re/Samples/Ubunchu!-KoAHD.cbz)
|
* [Kobo Aura HD](http://kcc.iosphe.re/Samples/Ubunchu!-KoAHD.cbz)
|
||||||
|
* [Kobo Aura H2O](http://kcc.iosphe.re/Samples/Ubunchu!-KoAH2O.cbz)
|
||||||
|
|
||||||
## CHANGELOG
|
## CHANGELOG
|
||||||
####1.0
|
####1.0
|
||||||
@@ -188,11 +192,11 @@ The app relies and includes the following scripts/binaries:
|
|||||||
* Added basic error reporting
|
* Added basic error reporting
|
||||||
|
|
||||||
####2.2:
|
####2.2:
|
||||||
* Added (valid!) ePub 2.0 output
|
* Added (valid!) EPUB 2.0 output
|
||||||
* Rename .zip files to .cbz to avoid overwriting
|
* Rename .zip files to .cbz to avoid overwriting
|
||||||
|
|
||||||
####2.3
|
####2.3
|
||||||
* Fixed win32 ePub generation, folder handling, filenames with spaces and subfolders
|
* Fixed win32 EPUB generation, folder handling, filenames with spaces and subfolders
|
||||||
|
|
||||||
####2.4
|
####2.4
|
||||||
* Use temporary directory as workdir (fixes converting from external volumes and zipfiles renaming)
|
* Use temporary directory as workdir (fixes converting from external volumes and zipfiles renaming)
|
||||||
@@ -200,22 +204,22 @@ The app relies and includes the following scripts/binaries:
|
|||||||
|
|
||||||
####2.5
|
####2.5
|
||||||
* Added --black-borders option to set added borders black when page's ratio is not the device's one (#11).
|
* 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)
|
* Fixes EPUB containing zipped itself (#10)
|
||||||
|
|
||||||
####2.6
|
####2.6
|
||||||
* Added --rotate option to rotate landscape images instead of splitting them (#16, #24)
|
* Added --rotate option to rotate landscape images instead of splitting them (#16, #24)
|
||||||
* Added --output option to customize ePub output dir/file (#22)
|
* 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)
|
* Add rendition:layout and rendition:orientation EPUB meta tags (supported by new kindlegen 2.8)
|
||||||
* Fixed natural sorting for files (#18)
|
* Fixed natural sorting for files (#18)
|
||||||
|
|
||||||
####2.7
|
####2.7
|
||||||
* Lots of GUI improvements (#27, #13)
|
* Lots of GUI improvements (#27, #13)
|
||||||
* Added gamma support within --gamma option (defaults to profile-specified gamma) (#26, #27)
|
* Added gamma support within --gamma option (defaults to profile-specified gamma) (#26, #27)
|
||||||
* Added --nodithering option to prevent dithering optimizations (#27)
|
* Added --nodithering option to prevent dithering optimizations (#27)
|
||||||
* Epub margins support (#30)
|
* EPUB margins support (#30)
|
||||||
* Fixed no file added if file has no spaces on Windows (#25)
|
* Fixed no file added if file has no spaces on Windows (#25)
|
||||||
* Gracefully exit if unrar missing (#15)
|
* Gracefully exit if unrar missing (#15)
|
||||||
* Do not call kindlegen if source epub is bigger than 320MB (#17)
|
* Do not call kindlegen if source EPUB is bigger than 320MB (#17)
|
||||||
* Get filetype from magic number (#14)
|
* Get filetype from magic number (#14)
|
||||||
* PDF conversion works again
|
* PDF conversion works again
|
||||||
|
|
||||||
@@ -229,7 +233,7 @@ The app relies and includes the following scripts/binaries:
|
|||||||
* Optimized archive extraction for zip/rar files (#40)
|
* Optimized archive extraction for zip/rar files (#40)
|
||||||
|
|
||||||
####2.9
|
####2.9
|
||||||
* Added support for generating a plain CBZ (skipping all the EPUB/Mobi generation) (#45)
|
* 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
|
* Prevent output file overwriting the source one: if a duplicate name is detected, append _kcc to the name
|
||||||
* Rarfile library updated to 2.6
|
* Rarfile library updated to 2.6
|
||||||
* Added GIF, TIFF and BMP to supported formats (#42)
|
* Added GIF, TIFF and BMP to supported formats (#42)
|
||||||
@@ -237,7 +241,7 @@ The app relies and includes the following scripts/binaries:
|
|||||||
|
|
||||||
####2.10:
|
####2.10:
|
||||||
* Multiprocessing support
|
* Multiprocessing support
|
||||||
* Kindle Fire support (color ePub/Mobi)
|
* Kindle Fire support (color EPUB/MOBI)
|
||||||
* Panel View support for horizontal content
|
* Panel View support for horizontal content
|
||||||
* Fixed panel order for horizontal pages when --rotate is enabled
|
* Fixed panel order for horizontal pages when --rotate is enabled
|
||||||
* Disabled cropping and page number cutting for blank pages
|
* Disabled cropping and page number cutting for blank pages
|
||||||
@@ -368,6 +372,11 @@ The app relies and includes the following scripts/binaries:
|
|||||||
* Fixed some MCD support bugs
|
* Fixed some MCD support bugs
|
||||||
* Default output format for Kindle DX is now CBZ
|
* Default output format for Kindle DX is now CBZ
|
||||||
|
|
||||||
|
####4.3:
|
||||||
|
* Added profiles for Kindle Voyage and Kobo Aura H2O
|
||||||
|
* Added missing features to CLI version
|
||||||
|
* Other minor bug fixes
|
||||||
|
|
||||||
## KNOWN ISSUES
|
## KNOWN ISSUES
|
||||||
Please check [wiki page](https://github.com/ciromattia/kcc/wiki/Known-issues).
|
Please check [wiki page](https://github.com/ciromattia/kcc/wiki/Known-issues).
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
# PERFORMANCE OF THIS SOFTWARE.
|
# PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
__version__ = '4.2.1'
|
__version__ = '4.3'
|
||||||
__license__ = 'ISC'
|
__license__ = 'ISC'
|
||||||
__copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>'
|
__copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
# PERFORMANCE OF THIS SOFTWARE.
|
# PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
__version__ = '4.2.1'
|
__version__ = '4.3'
|
||||||
__license__ = 'ISC'
|
__license__ = 'ISC'
|
||||||
__copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>'
|
__copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|||||||
4
kcc.iss
4
kcc.iss
@@ -1,5 +1,5 @@
|
|||||||
#define MyAppName "Kindle Comic Converter"
|
#define MyAppName "Kindle Comic Converter"
|
||||||
#define MyAppVersion "4.2.1"
|
#define MyAppVersion "4.3"
|
||||||
#define MyAppPublisher "Ciro Mattia Gonano, Paweł Jastrzębski"
|
#define MyAppPublisher "Ciro Mattia Gonano, Paweł Jastrzębski"
|
||||||
#define MyAppURL "http://kcc.iosphe.re/"
|
#define MyAppURL "http://kcc.iosphe.re/"
|
||||||
#define MyAppExeName "KCC.exe"
|
#define MyAppExeName "KCC.exe"
|
||||||
@@ -43,13 +43,11 @@ Name: "CB7association"; Description: "CB7"; GroupDescription: "File associations
|
|||||||
|
|
||||||
[Files]
|
[Files]
|
||||||
; x64 files
|
; x64 files
|
||||||
Source: "dist_64\imageformats\*"; DestDir: "{app}\imageformats\"; Flags: ignoreversion; Check: Is64BitInstallMode
|
|
||||||
Source: "dist_64\platforms\*"; DestDir: "{app}\platforms\"; Flags: ignoreversion; Check: Is64BitInstallMode
|
Source: "dist_64\platforms\*"; DestDir: "{app}\platforms\"; Flags: ignoreversion; Check: Is64BitInstallMode
|
||||||
Source: "dist_64\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
|
Source: "dist_64\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
|
||||||
Source: "dist_64\*.dll"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
|
Source: "dist_64\*.dll"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
|
||||||
Source: "other\vcredist_x64.exe"; DestDir: "{tmp}"; Flags: ignoreversion deleteafterinstall; Check: Is64BitInstallMode
|
Source: "other\vcredist_x64.exe"; DestDir: "{tmp}"; Flags: ignoreversion deleteafterinstall; Check: Is64BitInstallMode
|
||||||
; x86 files
|
; x86 files
|
||||||
Source: "dist\imageformats\*"; DestDir: "{app}\imageformats\"; Flags: ignoreversion; Check: not Is64BitInstallMode
|
|
||||||
Source: "dist\platforms\*"; DestDir: "{app}\platforms\"; Flags: ignoreversion; Check: not Is64BitInstallMode
|
Source: "dist\platforms\*"; DestDir: "{app}\platforms\"; Flags: ignoreversion; Check: not Is64BitInstallMode
|
||||||
Source: "dist\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
|
Source: "dist\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
|
||||||
Source: "dist\*.dll"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
|
Source: "dist\*.dll"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
|
||||||
|
|||||||
41
kcc.py
41
kcc.py
@@ -18,7 +18,7 @@
|
|||||||
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
# PERFORMANCE OF THIS SOFTWARE.
|
# PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
__version__ = '4.2.1'
|
__version__ = '4.3'
|
||||||
__license__ = 'ISC'
|
__license__ = 'ISC'
|
||||||
__copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>'
|
__copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
@@ -84,14 +84,14 @@ elif sys.platform.startswith('win'):
|
|||||||
os.chdir(os.path.dirname(os.path.abspath(sys.executable)))
|
os.chdir(os.path.dirname(os.path.abspath(sys.executable)))
|
||||||
|
|
||||||
# Implementing dummy stdout and stderr for frozen Windows release
|
# Implementing dummy stdout and stderr for frozen Windows release
|
||||||
class fakestd(object):
|
class FakeSTD(object):
|
||||||
def write(self, string):
|
def write(self, string):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def flush(self):
|
def flush(self):
|
||||||
pass
|
pass
|
||||||
sys.stdout = fakestd()
|
sys.stdout = FakeSTD()
|
||||||
sys.stderr = fakestd()
|
sys.stderr = FakeSTD()
|
||||||
else:
|
else:
|
||||||
os.environ['PATH'] = os.path.dirname(os.path.abspath(__file__)) + '/other/;' + os.environ['PATH']
|
os.environ['PATH'] = os.path.dirname(os.path.abspath(__file__)) + '/other/;' + os.environ['PATH']
|
||||||
os.chdir(os.path.dirname(os.path.abspath(__file__)))
|
os.chdir(os.path.dirname(os.path.abspath(__file__)))
|
||||||
@@ -103,36 +103,33 @@ class QApplicationMessaging(QtWidgets.QApplication):
|
|||||||
|
|
||||||
def __init__(self, argv):
|
def __init__(self, argv):
|
||||||
QtWidgets.QApplication.__init__(self, argv)
|
QtWidgets.QApplication.__init__(self, argv)
|
||||||
self._memory = QtCore.QSharedMemory(self)
|
|
||||||
self._memory.setKey('KCC')
|
|
||||||
if self._memory.attach():
|
|
||||||
self._running = True
|
|
||||||
else:
|
|
||||||
self._running = False
|
|
||||||
self._memory.create(1)
|
|
||||||
self._key = 'KCC'
|
self._key = 'KCC'
|
||||||
self._timeout = 1000
|
self._timeout = 1000
|
||||||
|
self._locked = False
|
||||||
|
socket = QtNetwork.QLocalSocket(self)
|
||||||
|
socket.connectToServer(self._key, QtCore.QIODevice.WriteOnly)
|
||||||
|
if not socket.waitForConnected(self._timeout):
|
||||||
self._server = QtNetwork.QLocalServer(self)
|
self._server = QtNetwork.QLocalServer(self)
|
||||||
if not self.isRunning():
|
|
||||||
# noinspection PyUnresolvedReferences
|
# noinspection PyUnresolvedReferences
|
||||||
self._server.newConnection.connect(self.handleMessage)
|
self._server.newConnection.connect(self.handleMessage)
|
||||||
self._server.listen(self._key)
|
self._server.listen(self._key)
|
||||||
|
else:
|
||||||
|
self._locked = True
|
||||||
|
socket.disconnectFromServer()
|
||||||
|
|
||||||
def shutdown(self):
|
def __del__(self):
|
||||||
if self._memory.isAttached():
|
if not self._locked:
|
||||||
self._memory.detach()
|
|
||||||
self._server.close()
|
self._server.close()
|
||||||
|
|
||||||
def event(self, e):
|
def event(self, e):
|
||||||
if e.type() == QtCore.QEvent.FileOpen:
|
if e.type() == QtCore.QEvent.FileOpen:
|
||||||
# noinspection PyArgumentList
|
|
||||||
self.messageFromOtherInstance.emit(bytes(e.file(), 'UTF-8'))
|
self.messageFromOtherInstance.emit(bytes(e.file(), 'UTF-8'))
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return QtWidgets.QApplication.event(self, e)
|
return QtWidgets.QApplication.event(self, e)
|
||||||
|
|
||||||
def isRunning(self):
|
def isRunning(self):
|
||||||
return self._running
|
return self._locked
|
||||||
|
|
||||||
def handleMessage(self):
|
def handleMessage(self):
|
||||||
socket = self._server.nextPendingConnection()
|
socket = self._server.nextPendingConnection()
|
||||||
@@ -140,18 +137,12 @@ class QApplicationMessaging(QtWidgets.QApplication):
|
|||||||
self.messageFromOtherInstance.emit(socket.readAll().data())
|
self.messageFromOtherInstance.emit(socket.readAll().data())
|
||||||
|
|
||||||
def sendMessage(self, message):
|
def sendMessage(self, message):
|
||||||
if self.isRunning():
|
|
||||||
socket = QtNetwork.QLocalSocket(self)
|
socket = QtNetwork.QLocalSocket(self)
|
||||||
socket.connectToServer(self._key, QtCore.QIODevice.WriteOnly)
|
socket.connectToServer(self._key, QtCore.QIODevice.WriteOnly)
|
||||||
if not socket.waitForConnected(self._timeout):
|
socket.waitForConnected(self._timeout)
|
||||||
return False
|
|
||||||
# noinspection PyArgumentList
|
|
||||||
socket.write(bytes(message, 'UTF-8'))
|
socket.write(bytes(message, 'UTF-8'))
|
||||||
if not socket.waitForBytesWritten(self._timeout):
|
socket.waitForBytesWritten(self._timeout)
|
||||||
return False
|
|
||||||
socket.disconnectFromServer()
|
socket.disconnectFromServer()
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
# Adding signals to QMainWindow
|
# Adding signals to QMainWindow
|
||||||
|
|||||||
147
kcc/KCC_gui.py
147
kcc/KCC_gui.py
@@ -17,7 +17,7 @@
|
|||||||
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
# PERFORMANCE OF THIS SOFTWARE.
|
# PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
__version__ = '4.2.1'
|
__version__ = '4.3'
|
||||||
__license__ = 'ISC'
|
__license__ = 'ISC'
|
||||||
__copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>'
|
__copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
@@ -36,12 +36,10 @@ from subprocess import STDOUT, PIPE
|
|||||||
from PyQt5 import QtGui, QtCore, QtWidgets
|
from PyQt5 import QtGui, QtCore, QtWidgets
|
||||||
from xml.dom.minidom import parse
|
from xml.dom.minidom import parse
|
||||||
from html.parser import HTMLParser
|
from html.parser import HTMLParser
|
||||||
from psutil import virtual_memory, Popen, Process
|
from psutil import Popen, Process
|
||||||
from uuid import uuid4
|
|
||||||
from copy import copy
|
from copy import copy
|
||||||
from .shared import md5Checksum
|
from .shared import md5Checksum
|
||||||
from . import comic2ebook
|
from . import comic2ebook
|
||||||
from . import dualmetafix
|
|
||||||
from . import KCC_rc_web
|
from . import KCC_rc_web
|
||||||
if sys.platform.startswith('darwin'):
|
if sys.platform.startswith('darwin'):
|
||||||
from . import KCC_ui_osx as KCC_ui
|
from . import KCC_ui_osx as KCC_ui
|
||||||
@@ -265,84 +263,14 @@ class ProgressThread(QtCore.QThread):
|
|||||||
self.running = False
|
self.running = False
|
||||||
|
|
||||||
|
|
||||||
class WorkerSignals(QtCore.QObject):
|
|
||||||
result = QtCore.pyqtSignal(list)
|
|
||||||
|
|
||||||
|
|
||||||
class KindleGenThread(QtCore.QRunnable):
|
|
||||||
def __init__(self, batch):
|
|
||||||
super(KindleGenThread, self).__init__()
|
|
||||||
self.signals = WorkerSignals()
|
|
||||||
self.work = batch
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
kindlegenErrorCode = 0
|
|
||||||
kindlegenError = ''
|
|
||||||
try:
|
|
||||||
if os.path.getsize(self.work) < 629145600:
|
|
||||||
output = Popen('kindlegen -dont_append_source -locale en "' + self.work + '"', stdout=PIPE,
|
|
||||||
stderr=STDOUT, shell=True)
|
|
||||||
for line in output.stdout:
|
|
||||||
line = line.decode('utf-8')
|
|
||||||
# ERROR: Generic error
|
|
||||||
if "Error(" in line:
|
|
||||||
kindlegenErrorCode = 1
|
|
||||||
kindlegenError = line
|
|
||||||
# ERROR: EPUB too big
|
|
||||||
if ":E23026:" in line:
|
|
||||||
kindlegenErrorCode = 23026
|
|
||||||
if kindlegenErrorCode > 0:
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
# ERROR: EPUB too big
|
|
||||||
kindlegenErrorCode = 23026
|
|
||||||
self.signals.result.emit([kindlegenErrorCode, kindlegenError, self.work])
|
|
||||||
except Exception as err:
|
|
||||||
# ERROR: KCC unknown generic error
|
|
||||||
kindlegenErrorCode = 1
|
|
||||||
kindlegenError = format(err)
|
|
||||||
self.signals.result.emit([kindlegenErrorCode, kindlegenError, self.work])
|
|
||||||
|
|
||||||
|
|
||||||
class DualMetaFixThread(QtCore.QRunnable):
|
|
||||||
def __init__(self, batch):
|
|
||||||
super(DualMetaFixThread, self).__init__()
|
|
||||||
self.signals = WorkerSignals()
|
|
||||||
self.work = batch
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
item = self.work
|
|
||||||
os.remove(item)
|
|
||||||
mobiPath = item.replace('.epub', '.mobi')
|
|
||||||
move(mobiPath, mobiPath + '_toclean')
|
|
||||||
try:
|
|
||||||
# noinspection PyArgumentList
|
|
||||||
dualmetafix.DualMobiMetaFix(mobiPath + '_toclean', mobiPath, bytes(str(uuid4()), 'UTF-8'))
|
|
||||||
self.signals.result.emit([True])
|
|
||||||
except Exception as err:
|
|
||||||
self.signals.result.emit([False, format(err)])
|
|
||||||
|
|
||||||
|
|
||||||
class WorkerThread(QtCore.QThread):
|
class WorkerThread(QtCore.QThread):
|
||||||
#noinspection PyArgumentList
|
# noinspection PyArgumentList
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
QtCore.QThread.__init__(self)
|
QtCore.QThread.__init__(self)
|
||||||
self.pool = QtCore.QThreadPool()
|
|
||||||
self.conversionAlive = False
|
self.conversionAlive = False
|
||||||
self.errors = False
|
self.errors = False
|
||||||
self.kindlegenErrorCode = [0]
|
self.kindlegenErrorCode = [0]
|
||||||
self.workerOutput = []
|
self.workerOutput = []
|
||||||
# Let's make sure that we don't fill the memory
|
|
||||||
availableMemory = virtual_memory().total/1000000000
|
|
||||||
if availableMemory <= 2:
|
|
||||||
self.threadNumber = 1
|
|
||||||
elif 2 < availableMemory <= 4:
|
|
||||||
self.threadNumber = 2
|
|
||||||
else:
|
|
||||||
self.threadNumber = 4
|
|
||||||
# Let's make sure that we don't use too many threads
|
|
||||||
if self.threadNumber > QtCore.QThread.idealThreadCount():
|
|
||||||
self.threadNumber = QtCore.QThread.idealThreadCount()
|
|
||||||
self.progressBarTick = MW.progressBarTick
|
self.progressBarTick = MW.progressBarTick
|
||||||
self.addMessage = MW.addMessage
|
self.addMessage = MW.addMessage
|
||||||
|
|
||||||
@@ -361,9 +289,11 @@ class WorkerThread(QtCore.QThread):
|
|||||||
MW.addTrayMessage.emit('Conversion interrupted.', 'Critical')
|
MW.addTrayMessage.emit('Conversion interrupted.', 'Critical')
|
||||||
MW.modeConvert.emit(1)
|
MW.modeConvert.emit(1)
|
||||||
|
|
||||||
def addResult(self, output):
|
def sanitizeTrace(self, traceback):
|
||||||
MW.progressBarTick.emit('tick')
|
return ''.join(format_tb(traceback))\
|
||||||
self.workerOutput.append(output)
|
.replace('C:\\Users\\AcidWeb\\Documents\\Projekty\\KCC\\', '')\
|
||||||
|
.replace('C:\\Python34\\', '')\
|
||||||
|
.replace('C:\\Python34_64\\', '')
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
MW.modeConvert.emit(0)
|
MW.modeConvert.emit(0)
|
||||||
@@ -385,10 +315,9 @@ class WorkerThread(QtCore.QThread):
|
|||||||
options.quality = 1
|
options.quality = 1
|
||||||
elif GUI.QualityBox.checkState() == 2:
|
elif GUI.QualityBox.checkState() == 2:
|
||||||
options.quality = 2
|
options.quality = 2
|
||||||
if str(GUI.FormatBox.currentText()) == 'CBZ':
|
options.format = str(GUI.FormatBox.currentText())
|
||||||
options.cbzoutput = True
|
|
||||||
if GUI.currentMode == 1:
|
if GUI.currentMode == 1:
|
||||||
if profile in ['KFHD', 'KFHD8', 'KFHDX', 'KFHDX8']:
|
if 'KFH' in profile:
|
||||||
options.upscale = True
|
options.upscale = True
|
||||||
|
|
||||||
# Advanced mode settings
|
# Advanced mode settings
|
||||||
@@ -410,10 +339,7 @@ class WorkerThread(QtCore.QThread):
|
|||||||
if GUI.WebtoonBox.isChecked():
|
if GUI.WebtoonBox.isChecked():
|
||||||
options.webtoon = True
|
options.webtoon = True
|
||||||
if float(GUI.GammaValue) > 0.09:
|
if float(GUI.GammaValue) > 0.09:
|
||||||
# noinspection PyTypeChecker
|
|
||||||
options.gamma = float(GUI.GammaValue)
|
options.gamma = float(GUI.GammaValue)
|
||||||
if str(GUI.FormatBox.currentText()) == 'MOBI':
|
|
||||||
options.batchsplit = True
|
|
||||||
|
|
||||||
# Other/custom settings.
|
# Other/custom settings.
|
||||||
if GUI.currentMode > 2:
|
if GUI.currentMode > 2:
|
||||||
@@ -462,7 +388,7 @@ class WorkerThread(QtCore.QThread):
|
|||||||
self.errors = True
|
self.errors = True
|
||||||
_, _, traceback = sys.exc_info()
|
_, _, traceback = sys.exc_info()
|
||||||
MW.showDialog.emit("Error during conversion %s:\n\n%s\n\nTraceback:\n%s"
|
MW.showDialog.emit("Error during conversion %s:\n\n%s\n\nTraceback:\n%s"
|
||||||
% (jobargv[-1], str(err), "".join(format_tb(traceback))), 'error')
|
% (jobargv[-1], str(err), self.sanitizeTrace(traceback)), 'error')
|
||||||
MW.addMessage.emit('Failed to create EPUB!', 'error', False)
|
MW.addMessage.emit('Failed to create EPUB!', 'error', False)
|
||||||
MW.addTrayMessage.emit('Failed to create EPUB!', 'Critical')
|
MW.addTrayMessage.emit('Failed to create EPUB!', 'Critical')
|
||||||
if not self.conversionAlive:
|
if not self.conversionAlive:
|
||||||
@@ -483,16 +409,10 @@ class WorkerThread(QtCore.QThread):
|
|||||||
MW.progressBarTick.emit('tick')
|
MW.progressBarTick.emit('tick')
|
||||||
MW.addMessage.emit('Creating MOBI files', 'info', False)
|
MW.addMessage.emit('Creating MOBI files', 'info', False)
|
||||||
GUI.progress.content = 'Creating MOBI files'
|
GUI.progress.content = 'Creating MOBI files'
|
||||||
self.workerOutput = []
|
work = []
|
||||||
# Number of KindleGen threads depends on the size of RAM
|
|
||||||
self.pool.setMaxThreadCount(self.threadNumber)
|
|
||||||
for item in outputPath:
|
for item in outputPath:
|
||||||
worker = KindleGenThread(item)
|
work.append([item])
|
||||||
worker.signals.result.connect(self.addResult)
|
self.workerOutput = comic2ebook.makeMOBI(work, self)
|
||||||
self.pool.start(worker)
|
|
||||||
self.pool.waitForDone()
|
|
||||||
while len(self.workerOutput) != len(outputPath):
|
|
||||||
sleep(0.1)
|
|
||||||
self.kindlegenErrorCode = [0]
|
self.kindlegenErrorCode = [0]
|
||||||
for errors in self.workerOutput:
|
for errors in self.workerOutput:
|
||||||
if errors[0] != 0:
|
if errors[0] != 0:
|
||||||
@@ -512,15 +432,9 @@ class WorkerThread(QtCore.QThread):
|
|||||||
MW.addMessage.emit('Processing MOBI files', 'info', False)
|
MW.addMessage.emit('Processing MOBI files', 'info', False)
|
||||||
GUI.progress.content = 'Processing MOBI files'
|
GUI.progress.content = 'Processing MOBI files'
|
||||||
self.workerOutput = []
|
self.workerOutput = []
|
||||||
# DualMetaFix is very fast and there is not reason to use multithreading.
|
|
||||||
self.pool.setMaxThreadCount(1)
|
|
||||||
for item in outputPath:
|
for item in outputPath:
|
||||||
worker = DualMetaFixThread(item)
|
self.workerOutput.append(comic2ebook.makeMOBIFix(item))
|
||||||
worker.signals.result.connect(self.addResult)
|
MW.progressBarTick.emit('tick')
|
||||||
self.pool.start(worker)
|
|
||||||
self.pool.waitForDone()
|
|
||||||
while len(self.workerOutput) != len(outputPath):
|
|
||||||
sleep(0.1)
|
|
||||||
for success in self.workerOutput:
|
for success in self.workerOutput:
|
||||||
if not success[0]:
|
if not success[0]:
|
||||||
self.errors = True
|
self.errors = True
|
||||||
@@ -1018,7 +932,6 @@ class KCCGUI(KCC_ui.Ui_KCC):
|
|||||||
'GammaSlider': float(self.GammaValue)*100})
|
'GammaSlider': float(self.GammaValue)*100})
|
||||||
self.settings.sync()
|
self.settings.sync()
|
||||||
self.tray.hide()
|
self.tray.hide()
|
||||||
APP.shutdown()
|
|
||||||
|
|
||||||
def handleMessage(self, message):
|
def handleMessage(self, message):
|
||||||
MW.raise_()
|
MW.raise_()
|
||||||
@@ -1121,21 +1034,19 @@ class KCCGUI(KCC_ui.Ui_KCC):
|
|||||||
self.p.ionice(1)
|
self.p.ionice(1)
|
||||||
|
|
||||||
self.profiles = {
|
self.profiles = {
|
||||||
|
"Kindle Voyage": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
||||||
|
'DefaultUpscale': False, 'Label': 'KV'},
|
||||||
"Kindle Paperwhite": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
"Kindle Paperwhite": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
||||||
'DefaultUpscale': False, 'Label': 'KHD'},
|
'DefaultUpscale': False, 'Label': 'KPW'},
|
||||||
"Kindle": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
"Kindle": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
||||||
'DefaultUpscale': False, 'Label': 'K345'},
|
'DefaultUpscale': False, 'Label': 'K345'},
|
||||||
"Kindle DX/DXG": {'Quality': False, 'ForceExpert': False, 'DefaultFormat': 2,
|
"Kindle DX/DXG": {'Quality': False, 'ForceExpert': False, 'DefaultFormat': 2,
|
||||||
'DefaultUpscale': False, 'Label': 'KDX'},
|
'DefaultUpscale': False, 'Label': 'KDX'},
|
||||||
"Kindle Fire": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
"K. Fire HD": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
||||||
'DefaultUpscale': False, 'Label': 'KF'},
|
|
||||||
"K. Fire HD 7\"": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
|
||||||
'DefaultUpscale': True, 'Label': 'KFHD'},
|
'DefaultUpscale': True, 'Label': 'KFHD'},
|
||||||
"K. Fire HD 8.9\"": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
"K. Fire HDX": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
||||||
'DefaultUpscale': True, 'Label': 'KFHD8'},
|
|
||||||
"K. Fire HDX 7\"": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
|
||||||
'DefaultUpscale': True, 'Label': 'KFHDX'},
|
'DefaultUpscale': True, 'Label': 'KFHDX'},
|
||||||
"K. Fire HDX 8.9\"": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
"K. Fire HDX 8.9": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
||||||
'DefaultUpscale': True, 'Label': 'KFHDX8'},
|
'DefaultUpscale': True, 'Label': 'KFHDX8'},
|
||||||
"Kobo Mini/Touch": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 2,
|
"Kobo Mini/Touch": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 2,
|
||||||
'DefaultUpscale': False, 'Label': 'KoMT'},
|
'DefaultUpscale': False, 'Label': 'KoMT'},
|
||||||
@@ -1145,6 +1056,8 @@ class KCCGUI(KCC_ui.Ui_KCC):
|
|||||||
'DefaultUpscale': False, 'Label': 'KoA'},
|
'DefaultUpscale': False, 'Label': 'KoA'},
|
||||||
"Kobo Aura HD": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 2,
|
"Kobo Aura HD": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 2,
|
||||||
'DefaultUpscale': False, 'Label': 'KoAHD'},
|
'DefaultUpscale': False, 'Label': 'KoAHD'},
|
||||||
|
"Kobo Aura H2O": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 2,
|
||||||
|
'DefaultUpscale': False, 'Label': 'KoAH2O'},
|
||||||
"Other": {'Quality': False, 'ForceExpert': True, 'DefaultFormat': 1,
|
"Other": {'Quality': False, 'ForceExpert': True, 'DefaultFormat': 1,
|
||||||
'DefaultUpscale': False, 'Label': 'OTHER'},
|
'DefaultUpscale': False, 'Label': 'OTHER'},
|
||||||
"Kindle for Android": {'Quality': False, 'ForceExpert': True, 'DefaultFormat': 0,
|
"Kindle for Android": {'Quality': False, 'ForceExpert': True, 'DefaultFormat': 0,
|
||||||
@@ -1155,26 +1068,26 @@ class KCCGUI(KCC_ui.Ui_KCC):
|
|||||||
'DefaultUpscale': False, 'Label': 'K2'}
|
'DefaultUpscale': False, 'Label': 'K2'}
|
||||||
}
|
}
|
||||||
profilesGUI = [
|
profilesGUI = [
|
||||||
|
"Kindle Voyage",
|
||||||
"Kindle Paperwhite",
|
"Kindle Paperwhite",
|
||||||
"Kindle",
|
"Kindle",
|
||||||
"Kindle DX/DXG",
|
|
||||||
"Separator",
|
"Separator",
|
||||||
"Kindle Fire",
|
"K. Fire HD",
|
||||||
"K. Fire HD 7\"",
|
"K. Fire HDX",
|
||||||
"K. Fire HD 8.9\"",
|
"K. Fire HDX 8.9",
|
||||||
"K. Fire HDX 7\"",
|
|
||||||
"K. Fire HDX 8.9\"",
|
|
||||||
"Separator",
|
"Separator",
|
||||||
"Kobo Mini/Touch",
|
"Kobo Mini/Touch",
|
||||||
"Kobo Glow",
|
"Kobo Glow",
|
||||||
"Kobo Aura",
|
"Kobo Aura",
|
||||||
"Kobo Aura HD",
|
"Kobo Aura HD",
|
||||||
|
"Kobo Aura H2O",
|
||||||
"Separator",
|
"Separator",
|
||||||
"Other",
|
"Other",
|
||||||
"Separator",
|
"Separator",
|
||||||
"Kindle for Android",
|
"Kindle for Android",
|
||||||
"Kindle 1",
|
"Kindle 1",
|
||||||
"Kindle 2",
|
"Kindle 2",
|
||||||
|
"Kindle DX/DXG",
|
||||||
]
|
]
|
||||||
|
|
||||||
statusBarLabel = QtWidgets.QLabel('<b><a href="http://kcc.iosphe.re/">HOMEPAGE</a> - <a href="https://github.'
|
statusBarLabel = QtWidgets.QLabel('<b><a href="http://kcc.iosphe.re/">HOMEPAGE</a> - <a href="https://github.'
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
__version__ = '4.2.1'
|
__version__ = '4.3'
|
||||||
__license__ = 'ISC'
|
__license__ = 'ISC'
|
||||||
__copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>'
|
__copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
# PERFORMANCE OF THIS SOFTWARE.
|
# PERFORMANCE OF THIS SOFTWARE.
|
||||||
#
|
#
|
||||||
|
|
||||||
__version__ = '4.2.1'
|
__version__ = '4.3'
|
||||||
__license__ = 'ISC'
|
__license__ = 'ISC'
|
||||||
__copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>'
|
__copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
@@ -38,6 +38,8 @@ from xml.dom.minidom import parse
|
|||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
from slugify import slugify as slugifyExt
|
from slugify import slugify as slugifyExt
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
from subprocess import STDOUT, PIPE
|
||||||
|
from psutil import Popen, virtual_memory
|
||||||
try:
|
try:
|
||||||
from PyQt5 import QtCore
|
from PyQt5 import QtCore
|
||||||
except ImportError:
|
except ImportError:
|
||||||
@@ -47,6 +49,7 @@ from . import comic2panel
|
|||||||
from . import image
|
from . import image
|
||||||
from . import cbxarchive
|
from . import cbxarchive
|
||||||
from . import pdfjpgextract
|
from . import pdfjpgextract
|
||||||
|
from . import dualmetafix
|
||||||
|
|
||||||
|
|
||||||
def main(argv=None):
|
def main(argv=None):
|
||||||
@@ -746,7 +749,7 @@ def sanitizePermissions(filetree):
|
|||||||
os.chmod(os.path.join(root, name), S_IWRITE | S_IREAD | S_IEXEC)
|
os.chmod(os.path.join(root, name), S_IWRITE | S_IREAD | S_IEXEC)
|
||||||
|
|
||||||
|
|
||||||
#noinspection PyUnboundLocalVariable
|
# noinspection PyUnboundLocalVariable
|
||||||
def splitDirectory(path):
|
def splitDirectory(path):
|
||||||
# Detect directory stucture
|
# Detect directory stucture
|
||||||
for root, dirs, files in walkLevel(os.path.join(path, 'OEBPS', 'Images'), 0):
|
for root, dirs, files in walkLevel(os.path.join(path, 'OEBPS', 'Images'), 0):
|
||||||
@@ -871,7 +874,7 @@ def detectCorruption(tmpPath, orgPath):
|
|||||||
for name in files:
|
for name in files:
|
||||||
if getImageFileName(name) is not None:
|
if getImageFileName(name) is not None:
|
||||||
path = os.path.join(root, name)
|
path = os.path.join(root, name)
|
||||||
pathOrg = os.path.join(orgPath, name)
|
pathOrg = orgPath + path.split('OEBPS' + os.path.sep + 'Images')[1]
|
||||||
if os.path.getsize(path) == 0:
|
if os.path.getsize(path) == 0:
|
||||||
rmtree(os.path.join(tmpPath, '..', '..'), True)
|
rmtree(os.path.join(tmpPath, '..', '..'), True)
|
||||||
raise RuntimeError('Image file %s is corrupted.' % pathOrg)
|
raise RuntimeError('Image file %s is corrupted.' % pathOrg)
|
||||||
@@ -945,7 +948,7 @@ def makeZIP(zipFilename, baseDir, isEPUB=False):
|
|||||||
|
|
||||||
|
|
||||||
def makeParser():
|
def makeParser():
|
||||||
"""Create and return an option parser set up with kcc's options."""
|
"""Create and return an option parser set up with KCC options."""
|
||||||
psr = OptionParser(usage="Usage: kcc-c2e [options] comic_file|comic_folder", add_help_option=False)
|
psr = OptionParser(usage="Usage: kcc-c2e [options] comic_file|comic_folder", add_help_option=False)
|
||||||
|
|
||||||
mainOptions = OptionGroup(psr, "MAIN")
|
mainOptions = OptionGroup(psr, "MAIN")
|
||||||
@@ -954,9 +957,9 @@ def makeParser():
|
|||||||
customProfileOptions = OptionGroup(psr, "CUSTOM PROFILE")
|
customProfileOptions = OptionGroup(psr, "CUSTOM PROFILE")
|
||||||
otherOptions = OptionGroup(psr, "OTHER")
|
otherOptions = OptionGroup(psr, "OTHER")
|
||||||
|
|
||||||
mainOptions.add_option("-p", "--profile", action="store", dest="profile", default="KHD",
|
mainOptions.add_option("-p", "--profile", action="store", dest="profile", default="KV",
|
||||||
help="Device profile (Choose one among K1, K2, K345, KDX, KHD, KF, KFHD, KFHD8, KFHDX,"
|
help="Device profile (Available options: K1, K2, K345, KDX, KPW, KV, KFHD, KFHDX, KFHDX8,"
|
||||||
" KFHDX8, KFA, KoMT, KoG, KoA, KoAHD) [Default=KHD]")
|
" KFA, KoMT, KoG, KoA, KoAHD, KoAH2O) [Default=KV]")
|
||||||
mainOptions.add_option("-q", "--quality", type="int", dest="quality", default="0",
|
mainOptions.add_option("-q", "--quality", type="int", dest="quality", default="0",
|
||||||
help="Quality of Panel View. 0 - Normal 1 - High 2 - Ultra [Default=0]")
|
help="Quality of Panel View. 0 - Normal 1 - High 2 - Ultra [Default=0]")
|
||||||
mainOptions.add_option("-m", "--manga-style", action="store_true", dest="righttoleft", default=False,
|
mainOptions.add_option("-m", "--manga-style", action="store_true", dest="righttoleft", default=False,
|
||||||
@@ -968,8 +971,8 @@ def makeParser():
|
|||||||
help="Output generated file to specified directory or file")
|
help="Output generated file to specified directory or file")
|
||||||
outputOptions.add_option("-t", "--title", action="store", dest="title", default="defaulttitle",
|
outputOptions.add_option("-t", "--title", action="store", dest="title", default="defaulttitle",
|
||||||
help="Comic title [Default=filename or directory name]")
|
help="Comic title [Default=filename or directory name]")
|
||||||
outputOptions.add_option("--cbz-output", action="store_true", dest="cbzoutput", default=False,
|
outputOptions.add_option("-f", "--format", action="store", dest="format", default="Auto",
|
||||||
help="Outputs a CBZ archive and does not generate EPUB")
|
help="Output format (Available options: Auto, MOBI, EPUB, CBZ) [Default=Auto]")
|
||||||
outputOptions.add_option("--batchsplit", action="store_true", dest="batchsplit", default=False,
|
outputOptions.add_option("--batchsplit", action="store_true", dest="batchsplit", default=False,
|
||||||
help="Split output into multiple files"),
|
help="Split output into multiple files"),
|
||||||
|
|
||||||
@@ -1016,13 +1019,22 @@ def checkOptions():
|
|||||||
global options
|
global options
|
||||||
options.panelview = True
|
options.panelview = True
|
||||||
options.bordersColor = None
|
options.bordersColor = None
|
||||||
|
if options.format == 'Auto':
|
||||||
|
if options.profile in ['K1', 'K2', 'K345', 'KPW', 'KV', 'KFHD', 'KFHDX', 'KFHDX8', 'KFA']:
|
||||||
|
options.format = 'MOBI'
|
||||||
|
elif options.profile in ['Other']:
|
||||||
|
options.format = 'EPUB'
|
||||||
|
elif options.profile in ['KDX', 'KoMT', 'KoG', 'KoA', 'KoAHD', 'KoAH2O']:
|
||||||
|
options.format = 'CBZ'
|
||||||
if options.white_borders:
|
if options.white_borders:
|
||||||
options.bordersColor = "white"
|
options.bordersColor = 'white'
|
||||||
if options.black_borders:
|
if options.black_borders:
|
||||||
options.bordersColor = "black"
|
options.bordersColor = 'black'
|
||||||
|
# Splitting MOBI is not optional
|
||||||
|
if options.format == 'MOBI':
|
||||||
|
options.batchsplit = True
|
||||||
# Disabling grayscale conversion for Kindle Fire family.
|
# Disabling grayscale conversion for Kindle Fire family.
|
||||||
if options.profile == 'KF' or options.profile == 'KFHD' or options.profile == 'KFHD8' or options.profile == 'KFHDX'\
|
if 'KFH' in options.profile or options.forcecolor:
|
||||||
or options.profile == 'KFHDX8' or options.forcecolor:
|
|
||||||
options.forcecolor = True
|
options.forcecolor = True
|
||||||
else:
|
else:
|
||||||
options.forcecolor = False
|
options.forcecolor = False
|
||||||
@@ -1049,10 +1061,10 @@ def checkOptions():
|
|||||||
print("ERROR: Kindle for Android profile require --customwidth and --customheight options!")
|
print("ERROR: Kindle for Android profile require --customwidth and --customheight options!")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
# CBZ files on Kindle DX/DXG support higher resolution
|
# CBZ files on Kindle DX/DXG support higher resolution
|
||||||
if options.profile == 'KDX' and options.cbzoutput:
|
if options.profile == 'KDX' and options.format == 'CBZ':
|
||||||
options.customheight = 1200
|
options.customheight = 1200
|
||||||
# Ultra mode don't work with CBZ format
|
# Ultra mode don't work with CBZ format
|
||||||
if options.quality == 2 and options.cbzoutput:
|
if options.quality == 2 and options.format == 'CBZ':
|
||||||
options.quality = 1
|
options.quality = 1
|
||||||
# Override profile data
|
# Override profile data
|
||||||
if options.customwidth != 0 or options.customheight != 0:
|
if options.customwidth != 0 or options.customheight != 0:
|
||||||
@@ -1069,12 +1081,35 @@ def checkOptions():
|
|||||||
options.profileData = image.ProfileData.Profiles[options.profile]
|
options.profileData = image.ProfileData.Profiles[options.profile]
|
||||||
|
|
||||||
|
|
||||||
|
def checkTools(source):
|
||||||
|
source = source.upper()
|
||||||
|
if source.endswith('.CBR') or source.endswith('.RAR'):
|
||||||
|
rarExitCode = Popen('unrar', stdout=PIPE, stderr=STDOUT, shell=True)
|
||||||
|
rarExitCode = rarExitCode.wait()
|
||||||
|
if rarExitCode != 0 and rarExitCode != 7:
|
||||||
|
print('\nUnRAR is missing!')
|
||||||
|
exit(1)
|
||||||
|
elif source.endswith('.CB7') or source.endswith('.7Z'):
|
||||||
|
sevenzaExitCode = Popen('7za', stdout=PIPE, stderr=STDOUT, shell=True)
|
||||||
|
sevenzaExitCode = sevenzaExitCode.wait()
|
||||||
|
if sevenzaExitCode != 0 and sevenzaExitCode != 7:
|
||||||
|
print('\n7za is missing!')
|
||||||
|
exit(1)
|
||||||
|
if options.format == 'MOBI':
|
||||||
|
kindleGenExitCode = Popen('kindlegen -locale en', stdout=PIPE, stderr=STDOUT, shell=True)
|
||||||
|
if kindleGenExitCode.wait() != 0:
|
||||||
|
print('\nKindleGen is missing!')
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
|
||||||
def makeBook(source, qtGUI=None):
|
def makeBook(source, qtGUI=None):
|
||||||
"""Generates EPUB/CBZ comic ebook from a bunch of images."""
|
"""Generates MOBI/EPUB/CBZ comic ebook from a bunch of images."""
|
||||||
global GUI
|
global GUI
|
||||||
GUI = qtGUI
|
GUI = qtGUI
|
||||||
if GUI:
|
if GUI:
|
||||||
GUI.progressBarTick.emit('1')
|
GUI.progressBarTick.emit('1')
|
||||||
|
else:
|
||||||
|
checkTools(source)
|
||||||
path = getWorkFolder(source)
|
path = getWorkFolder(source)
|
||||||
print("\nChecking images...")
|
print("\nChecking images...")
|
||||||
getComicInfo(os.path.join(path, "OEBPS", "Images"), source)
|
getComicInfo(os.path.join(path, "OEBPS", "Images"), source)
|
||||||
@@ -1092,7 +1127,7 @@ def makeBook(source, qtGUI=None):
|
|||||||
if GUI:
|
if GUI:
|
||||||
GUI.progressBarTick.emit('1')
|
GUI.progressBarTick.emit('1')
|
||||||
chapterNames = sanitizeTree(os.path.join(path, 'OEBPS', 'Images'))
|
chapterNames = sanitizeTree(os.path.join(path, 'OEBPS', 'Images'))
|
||||||
if 'Ko' in options.profile and options.cbzoutput:
|
if 'Ko' in options.profile and options.format == 'CBZ':
|
||||||
sanitizeTreeKobo(os.path.join(path, 'OEBPS', 'Images'))
|
sanitizeTreeKobo(os.path.join(path, 'OEBPS', 'Images'))
|
||||||
if options.batchsplit:
|
if options.batchsplit:
|
||||||
tomes = splitDirectory(path)
|
tomes = splitDirectory(path)
|
||||||
@@ -1101,7 +1136,7 @@ def makeBook(source, qtGUI=None):
|
|||||||
filepath = []
|
filepath = []
|
||||||
tomeNumber = 0
|
tomeNumber = 0
|
||||||
if GUI:
|
if GUI:
|
||||||
if options.cbzoutput:
|
if options.format == 'CBZ':
|
||||||
GUI.progressBarTick.emit('Compressing CBZ files')
|
GUI.progressBarTick.emit('Compressing CBZ files')
|
||||||
else:
|
else:
|
||||||
GUI.progressBarTick.emit('Compressing EPUB files')
|
GUI.progressBarTick.emit('Compressing EPUB files')
|
||||||
@@ -1112,8 +1147,7 @@ def makeBook(source, qtGUI=None):
|
|||||||
if len(tomes) > 1:
|
if len(tomes) > 1:
|
||||||
tomeNumber += 1
|
tomeNumber += 1
|
||||||
options.title = options.baseTitle + ' [' + str(tomeNumber) + '/' + str(len(tomes)) + ']'
|
options.title = options.baseTitle + ' [' + str(tomeNumber) + '/' + str(len(tomes)) + ']'
|
||||||
if options.cbzoutput:
|
if options.format == 'CBZ':
|
||||||
# if CBZ output wanted, compress all images and return filepath
|
|
||||||
print("\nCreating CBZ file...")
|
print("\nCreating CBZ file...")
|
||||||
if len(tomes) > 1:
|
if len(tomes) > 1:
|
||||||
filepath.append(getOutputFilename(source, options.output, '.cbz', ' ' + str(tomeNumber)))
|
filepath.append(getOutputFilename(source, options.output, '.cbz', ' ' + str(tomeNumber)))
|
||||||
@@ -1121,9 +1155,8 @@ def makeBook(source, qtGUI=None):
|
|||||||
filepath.append(getOutputFilename(source, options.output, '.cbz', ''))
|
filepath.append(getOutputFilename(source, options.output, '.cbz', ''))
|
||||||
makeZIP(tome + '_comic', os.path.join(tome, "OEBPS", "Images"))
|
makeZIP(tome + '_comic', os.path.join(tome, "OEBPS", "Images"))
|
||||||
else:
|
else:
|
||||||
print("\nCreating EPUB structure...")
|
print("\nCreating EPUB file...")
|
||||||
buildEPUB(tome, chapterNames, tomeNumber)
|
buildEPUB(tome, chapterNames, tomeNumber)
|
||||||
# actually zip the ePub
|
|
||||||
if len(tomes) > 1:
|
if len(tomes) > 1:
|
||||||
filepath.append(getOutputFilename(source, options.output, '.epub', ' ' + str(tomeNumber)))
|
filepath.append(getOutputFilename(source, options.output, '.epub', ' ' + str(tomeNumber)))
|
||||||
else:
|
else:
|
||||||
@@ -1133,4 +1166,92 @@ def makeBook(source, qtGUI=None):
|
|||||||
rmtree(tome, True)
|
rmtree(tome, True)
|
||||||
if GUI:
|
if GUI:
|
||||||
GUI.progressBarTick.emit('tick')
|
GUI.progressBarTick.emit('tick')
|
||||||
|
if not GUI and options.format == 'MOBI':
|
||||||
|
print("\nCreating MOBI file...")
|
||||||
|
work = []
|
||||||
|
for i in filepath:
|
||||||
|
work.append([i])
|
||||||
|
output = makeMOBI(work, GUI)
|
||||||
|
for errors in output:
|
||||||
|
if errors[0] != 0:
|
||||||
|
print('KINDLEGEN ERROR!')
|
||||||
|
print(errors)
|
||||||
return filepath
|
return filepath
|
||||||
|
for i in filepath:
|
||||||
|
output = makeMOBIFix(i)
|
||||||
|
if not output[0]:
|
||||||
|
print('DUALMETAFIX ERROR!')
|
||||||
|
return filepath
|
||||||
|
else:
|
||||||
|
os.remove(i.replace('.epub', '.mobi') + '_toclean')
|
||||||
|
return filepath
|
||||||
|
|
||||||
|
|
||||||
|
def makeMOBIFix(item):
|
||||||
|
os.remove(item)
|
||||||
|
mobiPath = item.replace('.epub', '.mobi')
|
||||||
|
move(mobiPath, mobiPath + '_toclean')
|
||||||
|
try:
|
||||||
|
dualmetafix.DualMobiMetaFix(mobiPath + '_toclean', mobiPath, bytes(str(uuid4()), 'UTF-8'))
|
||||||
|
return [True]
|
||||||
|
except Exception as err:
|
||||||
|
return [False, format(err)]
|
||||||
|
|
||||||
|
|
||||||
|
def makeMOBIWorkerTick(output):
|
||||||
|
makeMOBIWorkerOutput.append(output)
|
||||||
|
if output[0] != 0:
|
||||||
|
makeMOBIWorkerPool.terminate()
|
||||||
|
if GUI:
|
||||||
|
GUI.progressBarTick.emit('tick')
|
||||||
|
if not GUI.conversionAlive:
|
||||||
|
makeMOBIWorkerPool.terminate()
|
||||||
|
|
||||||
|
|
||||||
|
def makeMOBIWorker(item):
|
||||||
|
item = item[0]
|
||||||
|
kindlegenErrorCode = 0
|
||||||
|
kindlegenError = ''
|
||||||
|
try:
|
||||||
|
if os.path.getsize(item) < 629145600:
|
||||||
|
output = Popen('kindlegen -dont_append_source -locale en "' + item + '"',
|
||||||
|
stdout=PIPE, stderr=STDOUT, shell=True)
|
||||||
|
for line in output.stdout:
|
||||||
|
line = line.decode('utf-8')
|
||||||
|
# ERROR: Generic error
|
||||||
|
if "Error(" in line:
|
||||||
|
kindlegenErrorCode = 1
|
||||||
|
kindlegenError = line
|
||||||
|
# ERROR: EPUB too big
|
||||||
|
if ":E23026:" in line:
|
||||||
|
kindlegenErrorCode = 23026
|
||||||
|
if kindlegenErrorCode > 0:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
# ERROR: EPUB too big
|
||||||
|
kindlegenErrorCode = 23026
|
||||||
|
return [kindlegenErrorCode, kindlegenError, item]
|
||||||
|
except Exception as err:
|
||||||
|
# ERROR: KCC unknown generic error
|
||||||
|
kindlegenErrorCode = 1
|
||||||
|
kindlegenError = format(err)
|
||||||
|
return [kindlegenErrorCode, kindlegenError, item]
|
||||||
|
|
||||||
|
|
||||||
|
def makeMOBI(work, qtGUI=None):
|
||||||
|
global GUI, makeMOBIWorkerPool, makeMOBIWorkerOutput
|
||||||
|
GUI = qtGUI
|
||||||
|
makeMOBIWorkerOutput = []
|
||||||
|
availableMemory = virtual_memory().total/1000000000
|
||||||
|
if availableMemory <= 2:
|
||||||
|
threadNumber = 1
|
||||||
|
elif 2 < availableMemory <= 4:
|
||||||
|
threadNumber = 2
|
||||||
|
else:
|
||||||
|
threadNumber = 4
|
||||||
|
makeMOBIWorkerPool = Pool(threadNumber)
|
||||||
|
for i in work:
|
||||||
|
makeMOBIWorkerPool.apply_async(func=makeMOBIWorker, args=(i, ), callback=makeMOBIWorkerTick)
|
||||||
|
makeMOBIWorkerPool.close()
|
||||||
|
makeMOBIWorkerPool.join()
|
||||||
|
return makeMOBIWorkerOutput
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
# PERFORMANCE OF THIS SOFTWARE.
|
# PERFORMANCE OF THIS SOFTWARE.
|
||||||
#
|
#
|
||||||
|
|
||||||
__version__ = '4.2.1'
|
__version__ = '4.3'
|
||||||
__license__ = 'ISC'
|
__license__ = 'ISC'
|
||||||
__copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>'
|
__copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
@@ -118,7 +118,6 @@ def splitImageTick(output):
|
|||||||
splitWorkerPool.terminate()
|
splitWorkerPool.terminate()
|
||||||
|
|
||||||
|
|
||||||
#noinspection PyUnboundLocalVariable
|
|
||||||
def splitImage(work):
|
def splitImage(work):
|
||||||
try:
|
try:
|
||||||
path = work[0]
|
path = work[0]
|
||||||
@@ -165,6 +164,7 @@ def splitImage(work):
|
|||||||
for panel in panelsCleaned:
|
for panel in panelsCleaned:
|
||||||
panels.append(panel)
|
panels.append(panel)
|
||||||
if opt.debug:
|
if opt.debug:
|
||||||
|
# noinspection PyUnboundLocalVariable
|
||||||
debugImage.save(os.path.join(path, fileExpanded[0] + '-debug.png'), 'PNG')
|
debugImage.save(os.path.join(path, fileExpanded[0] + '-debug.png'), 'PNG')
|
||||||
|
|
||||||
# Create virtual pages
|
# Create virtual pages
|
||||||
|
|||||||
16
kcc/image.py
16
kcc/image.py
@@ -16,7 +16,7 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
__version__ = '4.2.1'
|
__version__ = '4.3'
|
||||||
__license__ = 'ISC'
|
__license__ = 'ISC'
|
||||||
__copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>'
|
__copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
@@ -85,18 +85,18 @@ class ProfileData:
|
|||||||
'K1': ("Kindle 1", (600, 670), Palette4, 1.8, (900, 1005)),
|
'K1': ("Kindle 1", (600, 670), Palette4, 1.8, (900, 1005)),
|
||||||
'K2': ("Kindle 2", (600, 670), Palette15, 1.8, (900, 1005)),
|
'K2': ("Kindle 2", (600, 670), Palette15, 1.8, (900, 1005)),
|
||||||
'K345': ("Kindle", (600, 800), Palette16, 1.8, (900, 1200)),
|
'K345': ("Kindle", (600, 800), Palette16, 1.8, (900, 1200)),
|
||||||
'KHD': ("Kindle Paperwhite", (758, 1024), Palette16, 1.8, (1137, 1536)),
|
|
||||||
'KDX': ("Kindle DX/DXG", (824, 1000), Palette16, 1.8, (1236, 1500)),
|
'KDX': ("Kindle DX/DXG", (824, 1000), Palette16, 1.8, (1236, 1500)),
|
||||||
'KF': ("Kindle Fire", (600, 1024), PalleteNull, 1.0, (900, 1536)),
|
'KPW': ("Kindle Paperwhite", (758, 1024), Palette16, 1.8, (1137, 1536)),
|
||||||
'KFHD': ("K. Fire HD 7\"", (800, 1280), PalleteNull, 1.0, (1200, 1920)),
|
'KV': ("Kindle Voyage", (1080, 1440), Palette16, 1.8, (1620, 2160)),
|
||||||
'KFHD8': ("K. Fire HD 8.9\"", (1200, 1920), PalleteNull, 1.0, (1800, 2880)),
|
'KFHD': ("K. Fire HD", (800, 1280), PalleteNull, 1.0, (1200, 1920)),
|
||||||
'KFHDX': ("K. Fire HDX 7\"", (1200, 1920), PalleteNull, 1.0, (1800, 2880)),
|
'KFHDX': ("K. Fire HDX", (1200, 1920), PalleteNull, 1.0, (1800, 2880)),
|
||||||
'KFHDX8': ("K. Fire HDX 8.9\"", (1600, 2560), PalleteNull, 1.0, (2400, 3840)),
|
'KFHDX8': ("K. Fire HDX 8.9", (1600, 2560), PalleteNull, 1.0, (2400, 3840)),
|
||||||
|
'KFA': ("Kindle for Android", (0, 0), PalleteNull, 1.0, (0, 0)),
|
||||||
'KoMT': ("Kobo Mini/Touch", (600, 800), Palette16, 1.8, (900, 1200)),
|
'KoMT': ("Kobo Mini/Touch", (600, 800), Palette16, 1.8, (900, 1200)),
|
||||||
'KoG': ("Kobo Glow", (768, 1024), Palette16, 1.8, (1152, 1536)),
|
'KoG': ("Kobo Glow", (768, 1024), Palette16, 1.8, (1152, 1536)),
|
||||||
'KoA': ("Kobo Aura", (758, 1024), Palette16, 1.8, (1137, 1536)),
|
'KoA': ("Kobo Aura", (758, 1024), Palette16, 1.8, (1137, 1536)),
|
||||||
'KoAHD': ("Kobo Aura HD", (1080, 1440), Palette16, 1.8, (1620, 2160)),
|
'KoAHD': ("Kobo Aura HD", (1080, 1440), Palette16, 1.8, (1620, 2160)),
|
||||||
'KFA': ("Kindle for Android", (0, 0), PalleteNull, 1.0, (0, 0)),
|
'KoAH2O': ("Kobo Aura H2O", (1080, 1430), Palette16, 1.8, (1620, 2145)),
|
||||||
'OTHER': ("Other", (0, 0), Palette16, 1.8, (0, 0)),
|
'OTHER': ("Other", (0, 0), Palette16, 1.8, (0, 0)),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
39
setup.py
39
setup.py
@@ -1,12 +1,12 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""
|
"""
|
||||||
cx_Freeze/py2app build script for KCC.
|
py2exe/py2app build script for KCC.
|
||||||
|
|
||||||
Usage (Mac OS X):
|
|
||||||
python setup.py py2app
|
|
||||||
|
|
||||||
Usage (Windows):
|
Usage (Windows):
|
||||||
python setup.py py2exe
|
python setup.py py2exe
|
||||||
|
|
||||||
|
Usage (Mac OS X):
|
||||||
|
python setup.py py2app
|
||||||
"""
|
"""
|
||||||
from sys import platform, version_info
|
from sys import platform, version_info
|
||||||
if version_info[0] != 3:
|
if version_info[0] != 3:
|
||||||
@@ -14,7 +14,7 @@ if version_info[0] != 3:
|
|||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
NAME = "KindleComicConverter"
|
NAME = "KindleComicConverter"
|
||||||
VERSION = "4.2.1"
|
VERSION = "4.3"
|
||||||
MAIN = "kcc.py"
|
MAIN = "kcc.py"
|
||||||
|
|
||||||
if platform == "darwin":
|
if platform == "darwin":
|
||||||
@@ -63,43 +63,22 @@ elif platform == "win32":
|
|||||||
suffix = '_64'
|
suffix = '_64'
|
||||||
else:
|
else:
|
||||||
suffix = ''
|
suffix = ''
|
||||||
additional_files = [('imageformats', ['C:\Python34' + suffix +
|
additional_files = [('platforms', ['C:\Python34' + suffix +
|
||||||
'\Lib\site-packages\PyQt5\plugins\imageformats\qgif.dll',
|
|
||||||
'C:\Python34' + suffix +
|
|
||||||
'\Lib\site-packages\PyQt5\plugins\imageformats\qico.dll',
|
|
||||||
'C:\Python34' + suffix +
|
|
||||||
'\Lib\site-packages\PyQt5\plugins\imageformats\qjpeg.dll',
|
|
||||||
'C:\Python34' + suffix +
|
|
||||||
'\Lib\site-packages\PyQt5\plugins\imageformats\qmng.dll',
|
|
||||||
'C:\Python34' + suffix +
|
|
||||||
'\Lib\site-packages\PyQt5\plugins\imageformats\qsvg.dll',
|
|
||||||
'C:\Python34' + suffix +
|
|
||||||
'\Lib\site-packages\PyQt5\plugins\imageformats\qtga.dll',
|
|
||||||
'C:\Python34' + suffix +
|
|
||||||
'\Lib\site-packages\PyQt5\plugins\imageformats\qtiff.dll',
|
|
||||||
'C:\Python34' + suffix +
|
|
||||||
'\Lib\site-packages\PyQt5\plugins\imageformats\qwbmp.dll']),
|
|
||||||
('platforms', ['C:\Python34' + suffix +
|
|
||||||
'\Lib\site-packages\PyQt5\plugins\platforms\qminimal.dll',
|
|
||||||
'C:\Python34' + suffix +
|
|
||||||
'\Lib\site-packages\PyQt5\plugins\platforms\qoffscreen.dll',
|
|
||||||
'C:\Python34' + suffix +
|
|
||||||
'\Lib\site-packages\PyQt5\plugins\platforms\qwindows.dll']),
|
'\Lib\site-packages\PyQt5\plugins\platforms\qwindows.dll']),
|
||||||
('', ['LICENSE.txt',
|
('', ['LICENSE.txt',
|
||||||
'other\\7za.exe',
|
'other\\7za.exe',
|
||||||
'other\\UnRAR.exe',
|
'other\\UnRAR.exe',
|
||||||
'other\\Additional-LICENSE.txt',
|
'other\\Additional-LICENSE.txt',
|
||||||
'other\\7za.exe',
|
|
||||||
'C:\Python34' + suffix + '\Lib\site-packages\PyQt5\libEGL.dll'])]
|
'C:\Python34' + suffix + '\Lib\site-packages\PyQt5\libEGL.dll'])]
|
||||||
extra_options = dict(
|
extra_options = dict(
|
||||||
options={'py2exe': {"bundle_files": 2,
|
options={'py2exe': {"bundle_files": 1,
|
||||||
"dll_excludes": ["tcl85.dll", "tk85.dll"],
|
"dll_excludes": ["tcl85.dll", "tk85.dll"],
|
||||||
"dist_dir": "dist" + suffix,
|
"dist_dir": "dist" + suffix,
|
||||||
"compressed": True,
|
"compressed": True,
|
||||||
"includes": ["sip"],
|
"includes": ["sip"],
|
||||||
"excludes": ["tkinter"],
|
"excludes": ["tkinter"],
|
||||||
"optimize": 2}},
|
"optimize": 2}},
|
||||||
windows=[{"script": "kcc.py",
|
windows=[{"script": MAIN,
|
||||||
"dest_base": "KCC",
|
"dest_base": "KCC",
|
||||||
"version": VERSION,
|
"version": VERSION,
|
||||||
"copyright": "Ciro Mattia Gonano, Pawel Jastrzebski © 2014",
|
"copyright": "Ciro Mattia Gonano, Pawel Jastrzebski © 2014",
|
||||||
@@ -114,7 +93,7 @@ else:
|
|||||||
print('Please use setup.sh to build Linux package.')
|
print('Please use setup.sh to build Linux package.')
|
||||||
exit()
|
exit()
|
||||||
|
|
||||||
#noinspection PyUnboundLocalVariable
|
# noinspection PyUnboundLocalVariable
|
||||||
setup(
|
setup(
|
||||||
name=NAME,
|
name=NAME,
|
||||||
version=VERSION,
|
version=VERSION,
|
||||||
|
|||||||
Reference in New Issue
Block a user