1
0
mirror of https://github.com/ciromattia/kcc synced 2026-04-15 21:48:44 +00:00

Compare commits

..

92 Commits
4.2.1 ... 4.6.2

Author SHA1 Message Date
Paweł Jastrzębski
c65e1c8dea Merge pull request #150 from ciromattia/dev
4.6.2
2015-07-14 18:01:51 +02:00
Paweł Jastrzębski
677622c103 Updated README + version bump 2015-07-14 18:01:02 +02:00
Paweł Jastrzębski
af0ebb85a0 Escape HTML in metadata (close #148) 2015-07-14 17:58:59 +02:00
Paweł Jastrzębski
8af029ac92 Fixed MOBI header (close #149) 2015-07-14 17:40:33 +02:00
Paweł Jastrzębski
a268e12a90 Merge pull request #147 from ciromattia/dev
4.6.1
2015-07-05 12:16:27 +02:00
Paweł Jastrzębski
d621335e6c Updated README + version bump 2015-07-05 12:15:35 +02:00
Paweł Jastrzębski
ec1d9c2d93 Added ComicRack Summary field parsing (close #146) 2015-07-05 07:49:48 +02:00
Paweł Jastrzębski
85b9dbbf83 Detect too small input images 2015-07-05 06:57:56 +02:00
Paweł Jastrzębski
feeced44bf Tweaked KEPUB renamer (close #144) 2015-06-28 19:20:38 +02:00
Paweł Jastrzębski
cbea18398b Fixed Kobo TOC (close #145) 2015-06-28 18:31:47 +02:00
Paweł Jastrzębski
4c9857f14d Merge pull request #143 from ciromattia/dev
4.6
2015-06-21 08:44:37 +02:00
Paweł Jastrzębski
6b58ef4557 Updated README + version bump 2015-06-21 08:29:22 +02:00
Paweł Jastrzębski
24d697c965 Dropped Kindle Fire support 2015-06-21 08:04:28 +02:00
Paweł Jastrzębski
8b07d4eb69 Added Kindle Paperwhite 3 profile 2015-06-18 16:21:48 +02:00
Paweł Jastrzębski
e6c5ac915f Changed Kobo default output to KEPUB (close #141) 2015-06-17 22:35:24 +02:00
Paweł Jastrzębski
b22e4757a3 EPUB 3.0 output 2015-06-17 20:22:04 +02:00
Paweł Jastrzębski
91b06016bb Dependency update 2015-06-15 22:19:08 +02:00
Paweł Jastrzębski
5631391245 Error handling tweak 2015-05-31 09:36:20 +02:00
Paweł Jastrzębski
c33887b7b7 Fixed yet another tray icon anomaly 2015-05-20 20:21:12 +02:00
Paweł Jastrzębski
8d82f58f09 Merge pull request #137 from ciromattia/dev
4.5.1
2015-05-09 09:29:42 +02:00
Paweł Jastrzębski
36985f5169 Detect broken Pillow (close #135) 2015-05-07 22:37:48 +02:00
Paweł Jastrzębski
9d190c1585 Updated README + version bump 2015-05-07 18:06:16 +02:00
Paweł Jastrzębski
3834850317 Tweaked metadata editor 2015-05-07 17:49:03 +02:00
Paweł Jastrzębski
84fc23b979 Fixed CBR parsing anomalies (close #133) 2015-04-27 18:50:14 +02:00
Paweł Jastrzębski
77748afdbd Fixed supid typo 2015-04-26 18:47:40 +02:00
Paweł Jastrzębski
431e2ffaf2 Binary blob cleanup 2015-04-26 15:59:43 +02:00
Paweł Jastrzębski
16df4cd083 Added Kobo Glow HD profile 2015-04-22 20:38:17 +02:00
Paweł Jastrzębski
1aa34347c1 Added page-progression-direction tag to EPUB spine 2015-03-17 11:02:28 +01:00
Paweł Jastrzębski
561af90b06 Updated README and Setup 2015-03-09 20:08:48 +01:00
Paweł Jastrzębski
00d239e1d8 Merge pull request #131 from ciromattia/dev
4.5
2015-03-08 18:08:15 +01:00
Paweł Jastrzębski
26bd2d3ed0 Version bump 2015-03-08 18:07:47 +01:00
Paweł Jastrzębski
e7aa49b70c Fixed bookmark drift caused by image splits 2015-03-08 18:06:27 +01:00
Paweł Jastrzębski
da41edc2f1 GUI tweak 2015-02-26 18:27:10 +01:00
fsteffek
ecbf60fb28 Add ComicInfo bookmarks -> EPUB chapter support
Bookmarks from ComicRack's ComicInfo.xml are now converted to EPUB
chapters. `Bookmark` is an attribute to the `Page` element in
ComicInfo.xml.

 * Works with flat directory structure (no sub-folders support)
2015-02-21 18:40:59 +01:00
Paweł Jastrzębski
57b571b6c2 Fixed CLI version 2015-02-21 18:30:54 +01:00
Paweł Jastrzębski
44bdc0245b Fool proofing file sorting 2015-02-21 18:25:55 +01:00
fsteffek
1ec07fe4ec Fix random order of chapter list (close #129)
Directories and files returned by walk() are not always sorted.
Currently we sort the filelist after creating the it. When walk()-ing
topdown (we do) the directory list can be modified in-place. By sorting
the directories and files before creating the filelist, we guarantee
a sorted chapter list.
2015-02-21 17:59:46 +01:00
Paweł Jastrzębski
5f8f7e0919 Merge pull request #128 from fsteffek/dev
Fixed first file detection
2015-02-20 10:01:34 +01:00
fsteffek
f404b9090d Set first image in folder as cover
The walk() function does not necessarily return filenames in
alphabetical order. This leads to a random cover image.

Sorting filenames before setting the cover images fixes this issue.
2015-02-19 22:33:25 +01:00
Paweł Jastrzębski
68521f7c63 Updated installer 2015-02-17 18:08:23 +01:00
Paweł Jastrzębski
f5dd813c4c General refactoring and tweaks 2015-02-14 09:47:14 +01:00
Paweł Jastrzębski
7924c492b3 Updated OSX and Linux GUI 2015-02-08 12:52:42 +01:00
Paweł Jastrzębski
2fc21c33e2 Added metadata editor 2015-02-08 11:53:55 +01:00
Paweł Jastrzębski
cb76504acb Updated installer 2015-02-01 08:57:24 +01:00
Paweł Jastrzębski
db6b0eddfe Completely replaced Virtual Panel View with Panel View 2015-01-31 11:10:01 +01:00
Paweł Jastrzębski
7d529a2acc Added Metadata editor class 2015-01-24 18:36:15 +01:00
Paweł Jastrzębski
ad3ff35aaa Yet another workaround for file lock problems (#125) 2015-01-24 10:07:27 +01:00
Paweł Jastrzębski
c62eeeb712 Re-enabled MCD support 2015-01-21 19:15:38 +01:00
Paweł Jastrzębski
5a36a13105 Replaced os.walk 2015-01-21 18:19:54 +01:00
Paweł Jastrzębski
12684d6562 Code cleanup 2015-01-20 21:45:22 +01:00
Paweł Jastrzębski
c5f68ae12a Merge pull request #124 from ciromattia/dev
4.4.1
2015-01-11 16:20:43 +01:00
Paweł Jastrzębski
7bd9c766cc Version bump 2015-01-11 16:20:01 +01:00
Paweł Jastrzębski
c6b1417d9c Added one Windows DLL 2015-01-11 16:17:04 +01:00
Paweł Jastrzębski
98bf28a713 Fixed OSX GUI anomalies 2015-01-10 11:09:28 +01:00
Paweł Jastrzębski
f2d6d5b458 Fixed upgrade freeze (close #123) 2015-01-05 10:47:21 +01:00
Paweł Jastrzębski
5de492ffb6 Overhauled dependency check 2015-01-05 08:43:15 +01:00
Paweł Jastrzębski
5c2c6ed825 Tweaked OSX hack 2015-01-04 18:59:12 +01:00
Paweł Jastrzębski
c2730ab01c Merge pull request #122 from ciromattia/dev
4.4
2015-01-04 14:57:09 +01:00
Paweł Jastrzębski
bfba66d47d Improved KindleGen detection 2015-01-04 14:53:14 +01:00
Paweł Jastrzębski
b5bc2f8e00 Updated README + version bump 2015-01-04 10:49:59 +01:00
Paweł Jastrzębski
917eaef548 GUI tweaks 2015-01-04 10:27:13 +01:00
Paweł Jastrzębski
3187ebb054 Generic processing improvements 2015-01-04 09:13:20 +01:00
Paweł Jastrzębski
b9276e9ede WebToon processing improvements 2015-01-04 09:11:46 +01:00
Paweł Jastrzębski
147d815057 Code cleanup 2015-01-04 09:09:33 +01:00
Paweł Jastrzębski
180123fee2 Improved 7zip detection 2015-01-03 09:17:00 +01:00
Paweł Jastrzębski
2768e622f2 PyQT 5.4 workarounds 2015-01-02 11:51:14 +01:00
Paweł Jastrzębski
b629b45d46 Pillow update 2015-01-02 09:55:34 +01:00
Paweł Jastrzębski
f66c83425c PyQT 5.4 update 2015-01-01 15:24:59 +01:00
Paweł Jastrzębski
68b4b7114d Added RAR5 support 2014-12-30 11:07:11 +01:00
Paweł Jastrzębski
36f8c82eaf Fixed OSX race condition 2014-12-30 11:00:21 +01:00
Paweł Jastrzębski
bd665c3261 Merge pull request #119 from ciromattia/4.x
4.3.1
2014-11-24 20:13:17 +01:00
Paweł Jastrzębski
94586fa590 Version bump 2014-11-24 19:07:50 +01:00
Paweł Jastrzębski
89806dfcfc Disabled MCD integration 2014-11-24 18:56:24 +01:00
Paweł Jastrzębski
c9eb73ab90 OS X: Miscellaneous fixes (close #115) 2014-11-24 18:47:53 +01:00
Paweł Jastrzębski
2edcc0369a Updated UnRAR 2014-11-22 15:22:31 +01:00
Paweł Jastrzębski
bc0a52b848 PEP 8 2014-11-21 22:46:43 +01:00
Paweł Jastrzębski
5ae72bf06d Fixed Kindle Voyage profile 2014-11-21 22:41:51 +01:00
Paweł Jastrzębski
24c32643c1 Tweaked glob support 2014-11-10 19:33:03 +01:00
Paweł Jastrzębski
40b988f964 Merge branch 'multifile' of git://github.com/theaquamarine/kcc into 4.x 2014-10-29 07:14:39 +01:00
blue
ac794eff85 Use glob to resolve file globs
For systems where the shell doesn't do glob expansion, eg Windows.
2014-10-28 18:34:14 +00:00
blue
eaa387a9d6 Add basic support for converting more >1 file 2014-10-28 16:51:31 +00:00
Paweł Jastrzębski
d0f5d6dac4 Tweaked title sorting 2014-10-17 14:15:35 +02:00
Paweł Jastrzębski
b174534c1c Merge pull request #113 from ciromattia/4.x
4.3
2014-09-29 18:05:32 +02:00
Paweł Jastrzębski
19d486a4ee Updated README 2014-09-28 22:01:22 +02:00
Paweł Jastrzębski
652762b709 Updated README + version bump 2014-09-28 13:23:40 +02:00
Paweł Jastrzębski
e6df87f8fd CLI: Added tool detection 2014-09-28 13:16:13 +02:00
Paweł Jastrzębski
1a9cd0beb5 Moved MOBI creation to main code (close #111) 2014-09-28 13:01:42 +02:00
Paweł Jastrzębski
108e351126 Refactored locking mechanism (close #112) 2014-09-27 11:44:42 +02:00
Paweł Jastrzębski
dfe3e10470 Updated setup 2014-09-22 18:35:53 +02:00
Paweł Jastrzębski
787ad9fa66 Updated multiple device profiles 2014-09-18 19:05:24 +02:00
Paweł Jastrzębski
f10e8869a9 Added Kobo Aura H2O profile 2014-09-03 07:16:26 +02:00
Paweł Jastrzębski
715ada328f Tweaked error reporting (close #109) 2014-08-24 09:56:59 +02:00
39 changed files with 7321 additions and 4461 deletions

27
KCC.qrc
View File

@@ -1,27 +0,0 @@
<RCC>
<qresource prefix="Icon">
<file>icons/comic2ebook.png</file>
</qresource>
<qresource prefix="Devices">
<file>icons/Kobo.png</file>
<file>icons/Other.png</file>
<file>icons/Kindle.png</file>
</qresource>
<qresource prefix="Formats">
<file>icons/CBZ.png</file>
<file>icons/EPUB.png</file>
<file>icons/MOBI.png</file>
</qresource>
<qresource prefix="Status">
<file>icons/error.png</file>
<file>icons/info.png</file>
<file>icons/warning.png</file>
</qresource>
<qresource prefix="Other">
<file>icons/list_background.png</file>
<file>icons/clear.png</file>
<file>icons/convert.png</file>
<file>icons/document_new.png</file>
<file>icons/folder_new.png</file>
</qresource>
</RCC>

View File

@@ -1,7 +1,7 @@
ISC LICENSE
Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
Copyright (c) 2013-2014 Paweł Jastrzębski <pawelj@iosphe.re>
Copyright (c) 2013-2015 Paweł Jastrzębski <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

469
README.md
View File

@@ -1,20 +1,19 @@
# KCC
**Kindle Comic Converter** is a Python app to convert comic 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
actually a comic to EPUB converter that every e-reader owner can happily use**_.
**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
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.
### 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.
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 ;-)
### Issues / new features / donations
If you have general questions about usage, feedback etc. please [post it here](http://www.mobileread.com/forums/showthread.php?t=207461).
If you have some **technical** problems using KCC please [file an issue here](https://github.com/ciromattia/kcc/issues/new).
If you can fix an open issue, fork & make a pull request.
If you want more chances an issue is fixes or your wanted feature added, consider [placing a bounty](https://www.bountysource.com/trackers/65571-ciromattia-kcc)!
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:
@@ -30,35 +29,33 @@ You can find the latest released binary at the following links:
- **Linux:** [http://kcc.iosphe.re/Linux/](http://kcc.iosphe.re/Linux/)
- **OS X (10.8+):** [http://kcc.iosphe.re/OSX/](http://kcc.iosphe.re/OSX/)
## INPUT FORMATS
**KCC** can understand and convert, at the moment, the following input types:
- Folders containing: PNG, JPG, GIF, TIFF or BMP files
- CBZ, ZIP
- CBR, RAR *(With `unrar` executable)*
- CB7, 7Z *(With `7za` executable)*
- PDF *(Extracting only contained JPG images)*
## DEPENDENCIES
Following software is required to run Linux version of **KCC** and/or bare sources:
- Python 3.3+
- [PyQt](http://www.riverbankcomputing.co.uk/software/pyqt/download5) 5.2.0+
- [Pillow](http://pypi.python.org/pypi/Pillow/) 2.8.2+
- [psutil](https://pypi.python.org/pypi/psutil) 3.0.0+
- [python-slugify](http://pypi.python.org/pypi/python-slugify) 1.1.2+
- [scandir](https://pypi.python.org/pypi/scandir) 1.1.0+
## OPTIONAL REQUIREMENTS
On Debian based distributions these two commands should install all needed dependencies:
```
sudo apt-get install python3 python3-dev python3-pip python3-pyqt5 libpng-dev libjpeg-dev p7zip-full unrar
sudo pip3 install pillow python-slugify psutil scandir
```
### Optional dependencies
- [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)*
- [UnRAR](http://www.rarlab.com/download.htm) *(For CBR/RAR support)*
- [7za](http://www.7-zip.org/download.html) *(For 7z/CB7 support)*
### For running from source:
- Python 3.3+
- [PyQt5](http://www.riverbankcomputing.co.uk/software/pyqt/download5) 5.2.0+
- [Pillow](http://pypi.python.org/pypi/Pillow/) 2.5.0+
- [psutil](https://pypi.python.org/pypi/psutil) 2.0+
- [python-slugify](http://pypi.python.org/pypi/python-slugify)
On Debian based distributions these two commands should install all dependencies:
```
sudo apt-get install python3 python3-dev python3-pip python3-pyqt5 libtiff-dev libpng-dev libjpeg-dev p7zip-full unrar
sudo pip3 install pillow python-slugify psutil
```
### For freezing code:
- Windows - [py2exe](https://pypi.python.org/pypi/py2exe) 0.9.2+
- OS X - [py2app](https://bitbucket.org/ronaldoussoren/py2app) 0.8.0+
## INPUT FORMATS
**KCC** can understand and convert, at the moment, the following input types:
- Folders containing: PNG, JPG or GIF files
- CBZ, ZIP
- CBR, RAR *(With `unrar` executable)*
- CB7, 7Z *(With `7za` executable)*
- PDF *(Only extracting JPG images)*
## USAGE
@@ -67,6 +64,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.
CLI version of **KCC** is intended for power users. It is not idiot-proof like GUI :-)
### Standalone `kcc-c2e.py` usage:
```
@@ -75,7 +74,8 @@ Usage: kcc-c2e [options] comic_file|comic_folder
Options:
MAIN:
-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, KoMT, KoG, KoGHD, KoA, KoAHD, KoAH2O) [Default=KV]
-q QUALITY, --quality=QUALITY
Quality of Panel View. 0 - Normal 1 - High 2 - Ultra [Default=0]
-m, --manga-style Manga style (Right-to-left reading and splitting)
@@ -86,7 +86,9 @@ Options:
Output generated file to specified directory or file
-t TITLE, --title=TITLE
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
PROCESSING:
@@ -134,134 +136,170 @@ Options:
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.
- `rarfile.py` script &copy; 2005-2011 **Marko Kreen** <markokr@gmail.com>. Released with ISC License.
- `rarfile.py` script &copy; 2005-2014 **Marko Kreen** <markokr@gmail.com>. Released with ISC License.
- `image.py` class from **Alex Yatskov**'s [Mangle](https://github.com/FooSoft/mangle/) with subsequent [proDOOMman](https://github.com/proDOOMman/Mangle)'s and [Birua](https://github.com/Birua/Mangle)'s patches.
- 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
* [Kindle Paperwhite](http://kcc.iosphe.re/Samples/Ubunchu!-KPW.mobi)
* [Kindle Paperwhite 3 / Voyage](http://kcc.iosphe.re/Samples/Ubunchu!-KV.mobi)
* [Kindle Paperwhite 1 / 2](http://kcc.iosphe.re/Samples/Ubunchu!-KPW.mobi)
* [Kindle](http://kcc.iosphe.re/Samples/Ubunchu!-K345.mobi)
* [Kindle DX/DXG](http://kcc.iosphe.re/Samples/Ubunchu!-KDX.mobi)
* [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 Glow](http://kcc.iosphe.re/Samples/Ubunchu!-KoG.cbz)
* [Kobo Aura](http://kcc.iosphe.re/Samples/Ubunchu!-KoA.cbz)
* [Kobo Aura HD](http://kcc.iosphe.re/Samples/Ubunchu!-KoAHD.cbz)
* [Kindle DX/DXG](http://kcc.iosphe.re/Samples/Ubunchu!-KDX.cbz)
* [Kobo Mini/Touch](http://kcc.iosphe.re/Samples/Ubunchu-KoMT.kepub.epub)
* [Kobo Glo](http://kcc.iosphe.re/Samples/Ubunchu-KoG.kepub.epub)
* [Kobo Glo HD](http://kcc.iosphe.re/Samples/Ubunchu-KoGHD.kepub.epub)
* [Kobo Aura](http://kcc.iosphe.re/Samples/Ubunchu-KoA.kepub.epub)
* [Kobo Aura HD](http://kcc.iosphe.re/Samples/Ubunchu-KoAHD.kepub.epub)
* [Kobo Aura H2O](http://kcc.iosphe.re/Samples/Ubunchu-KoAH2O.kepub.epub)
## CHANGELOG
####1.0
* Initial version
####4.6.2:
* Fixed critical MOBI header bug
* Fixed metadata encoding error
####1.1
* Added support for CBZ/CBR files in comic2ebook.py
####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
####1.1.1
* Added support for CBZ/CBR files in Kindle Comic Converter
####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
####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!
####4.5.1:
* Added Kobo Glo HD profile
* Fixed RAR/CBR parsing anomalies
* Minor bug fixes and tweaks
####1.3
* Fixed an issue in OPF generation for device resolution
* Reworked options system (call with -h option to get the inline help)
####4.5:
* Added simple ComicRack metadata editor
* Re-enabled Manga Cover Database support
* ComicRack bookmarks are now parsed
* Fixed glitches in Kindle Voyage profile
* Fixed problems with directory locks on Windows
* Fixed sorting anomalies
* Improved conversion speed
####1.4
* Added some options for controlling image optimization
* Further optimization (ImageOps, page numbering cut, autocontrast)
####4.4.1:
* Fixed problems with OSX GUI
* Added one missing DLL to Windows installer
####1.4.1
* Fixed a serious bug on resizing when img ratio was bigger than device one
####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
####1.5
* Added subfolder support for multiple chapters.
####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
####2.0
* GUI! AppleScript is gone and Tk is used to provide cross-platform GUI support.
####4.3:
* Added profiles for Kindle Voyage and Kobo Aura H2O
* Added missing features to CLI version
* Other minor bug fixes
####2.1
* Added basic error reporting
####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
####2.2:
* Added (valid!) ePub 2.0 output
* Rename .zip files to .cbz to avoid overwriting
####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
####2.3
* Fixed win32 ePub generation, folder handling, filenames with spaces and subfolders
####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
####2.4
* Use temporary directory as workdir (fixes converting from external volumes and zipfiles renaming)
* Fixed "add folders" from GUI.
####4.0.2:
* Fixed some Windows and OSX specific bugs
* Fixed problem with marigns when using HQ mode
####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)
####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
####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)
####4.0:
* KCC now use Python 3.3 and Qt 5.2
* Full UTF-8 awareness
* CBZ output now support Manga mode
* Improved Panel View support and margin color detection
* Added drag&drop support
* Output directory can be now selected
* Windows release now have auto-updater
* Names of chapters on Kindle should be now more user friendly
* Fixed OSX file association support
* Many extensive internal changes and tweaks
####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)
* Epub margins support (#30)
* Fixed no file added if file has no spaces on Windows (#25)
* Gracefully exit if unrar missing (#15)
* Do not call kindlegen if source epub is bigger than 320MB (#17)
* Get filetype from magic number (#14)
* PDF conversion works again
####3.7.2:
* Fixed problems with HQ mode
####2.8
* Updated rarfile library
* Panel View support + HQ support (#36) - new option: --nopanelviewhq
* Split profiles for K4NT and K4T
* Rewrite of Landscape Mode support (huge readability improvement for KPW)
* Upscale use now BILINEAR method
* Added generic CSS file
* Optimized archive extraction for zip/rar files (#40)
####3.7.1:
* Hotfixed Kobo profiles
####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)
####3.7:
* Added profiles for KOBO devices
* Improved Panel View support
* Improved WebToon splitter
* Improved margin color autodetection
* Tweaked EPUB output
* Fixed stretching option
* GUI tweaks and minor bugfixes
####2.10:
* Multiprocessing support
* Kindle Fire support (color ePub/Mobi)
* Panel View support for horizontal content
* Fixed panel order for horizontal pages when --rotate is enabled
* Disabled cropping and page number cutting for blank pages
* Fixed some slugify issues with specific file naming conventions (#50, #51)
####3.6.2:
* Fixed previous PNG output fix
* Fixed Panel View anomalies
####3.0:
* New QT GUI
* Merge with AWKCC
* Added ultra quality mode
* Added support for custom width/height
* Added option to disable color conversion
####3.6.1:
* Fixed PNG output
####3.1:
* Added profile: Kindle for Android
* Add file/directory dialogs now support multiselect
* Many small fixes and tweaks
####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
* Added ComicRack metadata parser
* Implemented new method to detect border color in non-webtoon comics
* Upscaling is now enabled by default for Kindle Fire HD/HDX
* Windows nad Linux releases now have tray icon
* Fixed Kindle Fire HDX 7" output
* Increased target resolution for Kindle DX/DXG CBZ output
####3.2:
* Too big EPUB files are now splitted before conversion to MOBI
* Added experimental parser of manga webtoons
* Improved error handling
####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.2.1:
* Hotfixed crash occurring on OS with Russian locale
####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
* Paths that contain UTF-8 characters are now supported
* Migrated to new version of Pillow library
* Merged DX and DXG profiles
* Many other minor bug fixes and GUI tweaks
####3.3:
* Margins are now automatically omitted in Panel View mode
@@ -277,100 +315,117 @@ The app relies and includes the following scripts/binaries:
* Windows release is now bundled with UnRAR and 7za
* Small GUI tweaks
####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
* Paths that contain UTF-8 characters are now supported
* Migrated to new version of Pillow library
* Merged DX and DXG profiles
* Many other minor bug fixes and GUI tweaks
####3.2:
* Too big EPUB files are now splitted before conversion to MOBI
* Added experimental parser of manga webtoons
* Improved error handling
####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.2.1:
* Hotfixed crash occurring on OS with Russian locale
####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
* Added ComicRack metadata parser
* Implemented new method to detect border color in non-webtoon comics
* Upscaling is now enabled by default for Kindle Fire HD/HDX
* Windows nad Linux releases now have tray icon
* Fixed Kindle Fire HDX 7" output
* Increased target resolution for Kindle DX/DXG CBZ output
####3.1:
* Added profile: Kindle for Android
* Add file/directory dialogs now support multiselect
* Many small fixes and tweaks
####3.6.1:
* Fixed PNG output
####3.0:
* New QT GUI
* Merge with AWKCC
* Added ultra quality mode
* Added support for custom width/height
* Added option to disable color conversion
####3.6.2:
* Fixed previous PNG output fix
* Fixed Panel View anomalies
####2.10:
* Multiprocessing support
* Kindle Fire support (color EPUB/MOBI)
* Panel View support for horizontal content
* Fixed panel order for horizontal pages when --rotate is enabled
* Disabled cropping and page number cutting for blank pages
* Fixed some slugify issues with specific file naming conventions (#50, #51)
####3.7:
* Added profiles for KOBO devices
* Improved Panel View support
* Improved WebToon splitter
* Improved margin color autodetection
* Tweaked EPUB output
* Fixed stretching option
* GUI tweaks and minor bugfixes
####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)
####3.7.1:
* Hotfixed Kobo profiles
####2.8
* Updated rarfile library
* Panel View support + HQ support (#36) - new option: --nopanelviewhq
* Split profiles for K4NT and K4T
* Rewrite of Landscape Mode support (huge readability improvement for KPW)
* Upscale use now BILINEAR method
* Added generic CSS file
* Optimized archive extraction for zip/rar files (#40)
####3.7.2:
* Fixed problems with HQ mode
####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)
* EPUB margins support (#30)
* Fixed no file added if file has no spaces on Windows (#25)
* Gracefully exit if unrar missing (#15)
* Do not call kindlegen if source EPUB is bigger than 320MB (#17)
* Get filetype from magic number (#14)
* PDF conversion works again
####4.0:
* KCC now use Python 3.3 and Qt 5.2
* Full UTF-8 awareness
* CBZ output now support Manga mode
* Improved Panel View support and margin color detection
* Added drag&drop support
* Output directory can be now selected
* Windows release now have auto-updater
* Names of chapters on Kindle should be now more user friendly
* Fixed OSX file association support
* Many extensive internal changes and tweaks
####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)
####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
####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)
####4.0.2:
* Fixed some Windows and OSX specific bugs
* Fixed problem with marigns when using HQ mode
####2.4
* Use temporary directory as workdir (fixes converting from external volumes and zipfiles renaming)
* Fixed "add folders" from GUI.
####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
####2.3
* Fixed win32 EPUB generation, folder handling, filenames with spaces and subfolders
####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
####2.2:
* Added (valid!) EPUB 2.0 output
* Rename .zip files to .cbz to avoid overwriting
####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
####2.1
* Added basic error reporting
####2.0
* GUI! AppleScript is gone and Tk is used to provide cross-platform GUI support.
####1.5
* Added subfolder support for multiple chapters.
####1.4.1
* Fixed a serious bug on resizing when img ratio was bigger than device one
####1.4
* Added some options for controlling image optimization
* Further optimization (ImageOps, page numbering cut, autocontrast)
####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
* 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
* Added support for CBZ/CBR files in Kindle Comic Converter
####1.1
* Added support for CBZ/CBR files in comic2ebook.py
####1.0
* Initial version
## KNOWN ISSUES
Please check [wiki page](https://github.com/ciromattia/kcc/wiki/Known-issues).
## COPYRIGHT
Copyright (c) 2012-2014 Ciro Mattia Gonano and Paweł Jastrzębski.
Copyright (c) 2012-2015 Ciro Mattia Gonano and Paweł Jastrzębski.
**KCC** is released under ISC LICENSE; see LICENSE.txt for further details.

View File

@@ -71,7 +71,7 @@
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Disable image optimizations.&lt;br/&gt;Input images must be already resized.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Disable image optimizations.&lt;br/&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Input images must be already resized.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>No optimisation</string>
@@ -110,7 +110,7 @@
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enable auto-splitting of webtoons like &lt;span style=&quot; font-style:italic;&quot;&gt;Tower of God&lt;/span&gt; or &lt;span style=&quot; font-style:italic;&quot;&gt;Noblesse&lt;/span&gt;.&lt;br/&gt;This mode was created for pages with a low width, high height and vertical panel flow.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Enable special parsing mode for WebToons.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Webtoon mode</string>
@@ -167,7 +167,7 @@
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Disable splitting and rotation.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Disable page splitting and rotation.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>No split/rotate</string>
@@ -241,7 +241,7 @@
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Shift+Click to select the output directory.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Shift+Click to select the output directory.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Convert</string>
@@ -269,6 +269,9 @@
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Add directory containing JPG, PNG or GIF files to queue.&lt;br/&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;CBR, CBZ and CB7 files inside will not be processed!&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Add directory</string>
</property>
@@ -295,6 +298,9 @@
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Add CBR, CBZ, CB7 or PDF file to queue.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Add file</string>
</property>
@@ -386,7 +392,7 @@
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Unchecked - Normal quality mode&lt;/span&gt;&lt;br/&gt;Maximal quality of images but very poor magnification quality.&lt;br/&gt;Use it only when zoom is not needed or output files needs to be small.&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Indeterminate - High quality mode&lt;/span&gt;&lt;br/&gt;In most cases high quality of images and magnification.&lt;br/&gt;Overall quality highly depends on the resolution of source files.&lt;br/&gt;On Kindle models older than Paperwhite non-zoomed images might be a little blurred.&lt;br/&gt;&lt;br/&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Checked - Ultra quality mode&lt;/span&gt;&lt;br/&gt;Highest possible quality. Output files will be big.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Quality of Panel View/zoom. Highly impact size of output file.&lt;br/&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;This option control only quality of magnification!&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>High/Ultra quality</string>
@@ -457,19 +463,13 @@
<height>18</height>
</size>
</property>
<property name="verticalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
<property name="horizontalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
</widget>
<widget class="QPushButton" name="BasicModeButton">
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<width>195</width>
<width>141</width>
<height>32</height>
</rect>
</property>
@@ -489,9 +489,9 @@
<widget class="QPushButton" name="AdvModeButton">
<property name="geometry">
<rect>
<x>217</x>
<x>260</x>
<y>10</y>
<width>195</width>
<width>151</width>
<height>32</height>
</rect>
</property>
@@ -661,7 +661,7 @@
</font>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Resolution of target device.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Resolution of target device.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Custom width: </string>
@@ -694,7 +694,7 @@
<bool>false</bool>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Resolution of target device.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Resolution of target device.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="inputMask">
<string>0000</string>
@@ -712,7 +712,7 @@
</font>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Resolution of target device.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Resolution of target device.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Custom height: </string>
@@ -745,7 +745,7 @@
<bool>false</bool>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Resolution of target device.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Resolution of target device.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="inputMask">
<string>0000</string>
@@ -758,6 +758,32 @@
</layout>
</widget>
</widget>
<widget class="QPushButton" name="EditorButton">
<property name="geometry">
<rect>
<x>160</x>
<y>10</y>
<width>91</width>
<height>32</height>
</rect>
</property>
<property name="font">
<font>
<family>DejaVu Sans</family>
<pointsize>9</pointsize>
</font>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string>Editor</string>
</property>
<property name="icon">
<iconset resource="KCC.qrc">
<normaloff>:/Other/icons/editor.png</normaloff>:/Other/icons/editor.png</iconset>
</property>
</widget>
<zorder>OptionsAdvanced</zorder>
<zorder>DeviceBox</zorder>
<zorder>FormatBox</zorder>
@@ -771,6 +797,7 @@
<zorder>AdvModeButton</zorder>
<zorder>OptionsAdvancedGamma</zorder>
<zorder>OptionsExpert</zorder>
<zorder>EditorButton</zorder>
<zorder>ProgressBar</zorder>
</widget>
<widget class="QStatusBar" name="statusBar">

View File

@@ -69,7 +69,7 @@
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Disable image optimizations.&lt;br/&gt;Input images must be already resized.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Disable image optimizations.&lt;br/&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Input images must be already resized.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>No optimisation</string>
@@ -110,7 +110,7 @@
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enable auto-splitting of webtoons like &lt;span style=&quot; font-style:italic;&quot;&gt;Tower of God &lt;/span&gt;or &lt;span style=&quot; font-style:italic;&quot;&gt;Noblesse&lt;/span&gt;.&lt;br/&gt;This mode was created for pages with a low width, high height and vertical panel flow.&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Enable special parsing mode for WebToons.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Webtoon mode</string>
@@ -170,7 +170,7 @@
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Disable splitting and rotation.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Disable page splitting and rotation.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>No split/rotate</string>
@@ -220,7 +220,7 @@
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Output format.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Output format.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
<widget class="QPushButton" name="ConvertButton">
@@ -244,7 +244,7 @@
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Shift+Click to select the output directory.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Shift+Click to select the output directory.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Convert</string>
@@ -272,6 +272,9 @@
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Add directory containing JPG, PNG or GIF files to queue.&lt;br/&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;CBR, CBZ and CB7 files inside will not be processed!&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Add directory</string>
</property>
@@ -298,6 +301,9 @@
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Add CBR, CBZ, CB7 or PDF file to queue.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Add file</string>
</property>
@@ -391,7 +397,7 @@
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Unchecked - Normal quality mode&lt;/span&gt;&lt;br/&gt;Maximal quality of images but very poor magnification quality.&lt;br/&gt;Use it only when zoom is not needed or output files needs to be small.&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Indeterminate - High quality mode&lt;/span&gt;&lt;br/&gt;In most cases high quality of images and magnification.&lt;br/&gt;Overall quality highly depends on the resolution of source files.&lt;br/&gt;On Kindle models older than Paperwhite non-zoomed images might be a little blurred.&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Checked - Ultra quality mode&lt;/span&gt;&lt;br/&gt;Highest possible quality. Output files will be big.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Quality of Panel View/zoom. Highly impact size of output file.&lt;br/&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;This option control only quality of magnification!&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>High/Ultra quality</string>
@@ -456,19 +462,13 @@
<property name="selectionMode">
<enum>QAbstractItemView::NoSelection</enum>
</property>
<property name="verticalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
<property name="horizontalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
</widget>
<widget class="QPushButton" name="BasicModeButton">
<property name="geometry">
<rect>
<x>5</x>
<y>10</y>
<width>210</width>
<width>156</width>
<height>41</height>
</rect>
</property>
@@ -490,9 +490,9 @@
<widget class="QPushButton" name="AdvModeButton">
<property name="geometry">
<rect>
<x>207</x>
<x>260</x>
<y>10</y>
<width>210</width>
<width>156</width>
<height>41</height>
</rect>
</property>
@@ -773,9 +773,34 @@
</layout>
</widget>
</widget>
<widget class="QPushButton" name="EditorButton">
<property name="geometry">
<rect>
<x>160</x>
<y>10</y>
<width>101</width>
<height>41</height>
</rect>
</property>
<property name="font">
<font>
<family>Lucida Grande</family>
<pointsize>12</pointsize>
</font>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string>Editor</string>
</property>
<property name="icon">
<iconset resource="KCC.qrc">
<normaloff>:/Other/icons/editor.png</normaloff>:/Other/icons/editor.png</iconset>
</property>
</widget>
<zorder>BasicModeButton</zorder>
<zorder>AdvModeButton</zorder>
<zorder>ProgressBar</zorder>
<zorder>JobList</zorder>
<zorder>OptionsAdvanced</zorder>
<zorder>DeviceBox</zorder>
@@ -787,6 +812,8 @@
<zorder>OptionsBasic</zorder>
<zorder>OptionsAdvancedGamma</zorder>
<zorder>OptionsExpert</zorder>
<zorder>EditorButton</zorder>
<zorder>ProgressBar</zorder>
</widget>
<widget class="QStatusBar" name="statusBar">
<property name="font">

28
gui/KCC.qrc Normal file
View File

@@ -0,0 +1,28 @@
<RCC>
<qresource prefix="Icon">
<file>../icons/comic2ebook.png</file>
</qresource>
<qresource prefix="Devices">
<file>../icons/Kobo.png</file>
<file>../icons/Other.png</file>
<file>../icons/Kindle.png</file>
</qresource>
<qresource prefix="Formats">
<file>../icons/CBZ.png</file>
<file>../icons/EPUB.png</file>
<file>../icons/MOBI.png</file>
</qresource>
<qresource prefix="Status">
<file>../icons/error.png</file>
<file>../icons/info.png</file>
<file>../icons/warning.png</file>
</qresource>
<qresource prefix="Other">
<file>../icons/editor.png</file>
<file>../icons/list_background.png</file>
<file>../icons/clear.png</file>
<file>../icons/convert.png</file>
<file>../icons/document_new.png</file>
<file>../icons/folder_new.png</file>
</qresource>
</RCC>

View File

@@ -65,7 +65,7 @@
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Disable image optimizations.&lt;br/&gt;Input images must be already resized.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Disable image optimizations.&lt;br/&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Input images must be already resized.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>No optimisation</string>
@@ -94,7 +94,7 @@
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style=&quot;white-space:pre&quot;&gt;Enable auto-splitting of webtoons like &lt;span style=&quot; font-style:italic;&quot;&gt;Tower of God&lt;/span&gt; or &lt;span style=&quot; font-style:italic;&quot;&gt;Noblesse&lt;/span&gt;.&lt;br/&gt;This mode is created for pages with a low width, high height and vertical panel flow.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Enable special parsing mode for WebToons.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Webtoon mode</string>
@@ -136,7 +136,7 @@
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Disable splitting and rotation.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Disable page splitting and rotation.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>No split/rotate</string>
@@ -234,6 +234,9 @@
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Add directory containing JPG, PNG or GIF files to queue.&lt;br/&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;CBR, CBZ and CB7 files inside will not be processed!&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Add directory</string>
</property>
@@ -259,6 +262,9 @@
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Add CBR, CBZ, CB7 or PDF file to queue.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Add file</string>
</property>
@@ -338,7 +344,7 @@
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style=&quot;white-space:pre&quot;&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Unchecked - Normal quality mode&lt;br/&gt;&lt;/span&gt;Maximal quality of images but very poor magnification quality.&lt;br/&gt;Use it only when zoom is not needed or output files needs to be small.&lt;/p&gt;&lt;p style=&quot;white-space:pre&quot;&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Indeterminate - High quality mode&lt;br/&gt;&lt;/span&gt;In most cases high quality of images and magnification.&lt;br/&gt;Overall quality highly depends on the resolution of source files.&lt;br/&gt;On Kindle models older than Paperwhite non-zoomed images might be a little blurred.&lt;/p&gt;&lt;p style=&quot;white-space:pre&quot;&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Checked - Ultra quality mode&lt;br/&gt;&lt;/span&gt;Highest possible quality. Output files will be big.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Quality of Panel View/zoom. Highly impact size of output file.&lt;br/&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;This option control only quality of magnification!&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>High/Ultra quality</string>
@@ -391,19 +397,13 @@
<property name="selectionMode">
<enum>QAbstractItemView::NoSelection</enum>
</property>
<property name="verticalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
<property name="horizontalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
</widget>
<widget class="QPushButton" name="BasicModeButton">
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<width>195</width>
<width>141</width>
<height>32</height>
</rect>
</property>
@@ -422,9 +422,9 @@
<widget class="QPushButton" name="AdvModeButton">
<property name="geometry">
<rect>
<x>217</x>
<x>261</x>
<y>10</y>
<width>195</width>
<width>151</width>
<height>32</height>
</rect>
</property>
@@ -647,6 +647,31 @@
</layout>
</widget>
</widget>
<widget class="QPushButton" name="EditorButton">
<property name="geometry">
<rect>
<x>160</x>
<y>10</y>
<width>91</width>
<height>32</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>9</pointsize>
</font>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string>Editor</string>
</property>
<property name="icon">
<iconset resource="KCC.qrc">
<normaloff>:/Other/icons/editor.png</normaloff>:/Other/icons/editor.png</iconset>
</property>
</widget>
<zorder>OptionsAdvanced</zorder>
<zorder>DeviceBox</zorder>
<zorder>FormatBox</zorder>
@@ -660,6 +685,7 @@
<zorder>AdvModeButton</zorder>
<zorder>OptionsAdvancedGamma</zorder>
<zorder>OptionsExpert</zorder>
<zorder>EditorButton</zorder>
<zorder>ProgressBar</zorder>
</widget>
<widget class="QStatusBar" name="statusBar">

226
gui/MetaEditor-Linux.ui Normal file
View File

@@ -0,0 +1,226 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MetaEditorDialog</class>
<widget class="QDialog" name="MetaEditorDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>320</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>400</width>
<height>320</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>400</width>
<height>320</height>
</size>
</property>
<property name="windowTitle">
<string>Metadata editor</string>
</property>
<property name="windowIcon">
<iconset resource="KCC.qrc">
<normaloff>:/Icon/icons/comic2ebook.png</normaloff>:/Icon/icons/comic2ebook.png</iconset>
</property>
<widget class="QWidget" name="horizontalLayoutWidget">
<property name="geometry">
<rect>
<x>10</x>
<y>280</y>
<width>381</width>
<height>31</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="StatusLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>10</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="styleSheet">
<string notr="true">color: rgb(255, 0, 0);</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="OKButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Save</string>
</property>
<property name="icon">
<iconset resource="KCC.qrc">
<normaloff>:/Other/icons/convert.png</normaloff>:/Other/icons/convert.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="CancelButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Cancel</string>
</property>
<property name="icon">
<iconset resource="KCC.qrc">
<normaloff>:/Other/icons/clear.png</normaloff>:/Other/icons/clear.png</iconset>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QFrame" name="EditorFrame">
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<width>381</width>
<height>271</height>
</rect>
</property>
<widget class="QWidget" name="formLayoutWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>381</width>
<height>266</height>
</rect>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="1" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Series:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="SeriesLine"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Volume:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="VolumeLine"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Number:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="NumberLine"/>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Writer:</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLineEdit" name="WriterLine"/>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Penciller:</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLineEdit" name="PencillerLine"/>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Inker:</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLineEdit" name="InkerLine"/>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Colorist:</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QLineEdit" name="ColoristLine"/>
</item>
<item row="8" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/ciromattia/kcc/wiki/Manga-Cover-Database-support&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;MUid:&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QLineEdit" name="MUidLine"/>
</item>
</layout>
</widget>
</widget>
<zorder>horizontalLayoutWidget</zorder>
<zorder>EditorFrame</zorder>
<zorder>StatusLabel</zorder>
</widget>
<resources>
<include location="KCC.qrc"/>
</resources>
<connections/>
</ui>

223
gui/MetaEditor-OSX.ui Normal file
View File

@@ -0,0 +1,223 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MetaEditorDialog</class>
<widget class="QDialog" name="MetaEditorDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>295</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>400</width>
<height>295</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>400</width>
<height>295</height>
</size>
</property>
<property name="windowTitle">
<string>Metadata editor</string>
</property>
<property name="windowIcon">
<iconset resource="KCC.qrc">
<normaloff>:/Icon/icons/comic2ebook.png</normaloff>:/Icon/icons/comic2ebook.png</iconset>
</property>
<widget class="QWidget" name="horizontalLayoutWidget">
<property name="geometry">
<rect>
<x>10</x>
<y>260</y>
<width>381</width>
<height>32</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="StatusLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>10</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="styleSheet">
<string notr="true">color: rgb(255, 0, 0);</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="OKButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Save</string>
</property>
<property name="icon">
<iconset resource="KCC.qrc">
<normaloff>:/Other/icons/convert.png</normaloff>:/Other/icons/convert.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="CancelButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Cancel</string>
</property>
<property name="icon">
<iconset resource="KCC.qrc">
<normaloff>:/Other/icons/clear.png</normaloff>:/Other/icons/clear.png</iconset>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QFrame" name="EditorFrame">
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<width>381</width>
<height>251</height>
</rect>
</property>
<widget class="QWidget" name="formLayoutWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>381</width>
<height>250</height>
</rect>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="1" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Series:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="SeriesLine"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Volume:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="VolumeLine"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Number:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="NumberLine"/>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Writer:</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLineEdit" name="WriterLine"/>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Penciller:</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLineEdit" name="PencillerLine"/>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Inker:</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLineEdit" name="InkerLine"/>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Colorist:</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QLineEdit" name="ColoristLine"/>
</item>
<item row="8" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/ciromattia/kcc/wiki/Manga-Cover-Database-support&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;MUid:&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QLineEdit" name="MUidLine"/>
</item>
</layout>
</widget>
</widget>
</widget>
<resources>
<include location="KCC.qrc"/>
</resources>
<connections/>
</ui>

222
gui/MetaEditor.ui Normal file
View File

@@ -0,0 +1,222 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MetaEditorDialog</class>
<widget class="QDialog" name="MetaEditorDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>260</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>400</width>
<height>260</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>400</width>
<height>260</height>
</size>
</property>
<property name="windowTitle">
<string>Metadata editor</string>
</property>
<property name="windowIcon">
<iconset resource="KCC.qrc">
<normaloff>:/Icon/icons/comic2ebook.png</normaloff>:/Icon/icons/comic2ebook.png</iconset>
</property>
<widget class="QWidget" name="horizontalLayoutWidget">
<property name="geometry">
<rect>
<x>10</x>
<y>220</y>
<width>381</width>
<height>31</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="StatusLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="styleSheet">
<string notr="true">color: rgb(255, 0, 0);</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="OKButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Save</string>
</property>
<property name="icon">
<iconset resource="KCC.qrc">
<normaloff>:/Other/icons/convert.png</normaloff>:/Other/icons/convert.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="CancelButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Cancel</string>
</property>
<property name="icon">
<iconset resource="KCC.qrc">
<normaloff>:/Other/icons/clear.png</normaloff>:/Other/icons/clear.png</iconset>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QFrame" name="EditorFrame">
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<width>381</width>
<height>211</height>
</rect>
</property>
<widget class="QWidget" name="formLayoutWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>381</width>
<height>211</height>
</rect>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="1" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Series:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="SeriesLine"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Volume:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="VolumeLine"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Number:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="NumberLine"/>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Writer:</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLineEdit" name="WriterLine"/>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Penciller:</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLineEdit" name="PencillerLine"/>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Inker:</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLineEdit" name="InkerLine"/>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Colorist:</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QLineEdit" name="ColoristLine"/>
</item>
<item row="8" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/ciromattia/kcc/wiki/Manga-Cover-Database-support&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;MUid:&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QLineEdit" name="MUidLine"/>
</item>
</layout>
</widget>
</widget>
</widget>
<resources>
<include location="KCC.qrc"/>
</resources>
<connections/>
</ui>

BIN
icons/editor.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -2,7 +2,7 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
# Copyright (c) 2013-2014 Pawel Jastrzebski <pawelj@iosphe.re>
# Copyright (c) 2013-2015 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
@@ -18,55 +18,20 @@
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
__version__ = '4.2.1'
__license__ = 'ISC'
__copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>'
__docformat__ = 'restructuredtext en'
import sys
if sys.version_info[0] != 3:
print('ERROR: This is Python 3 script!')
exit(1)
# Dependency check
missing = []
try:
# noinspection PyUnresolvedReferences
import psutil
if tuple(map(int, ('2.0.0'.split(".")))) > tuple(map(int, psutil.version_info)):
missing.append('psutil 2.0.0+')
except ImportError:
missing.append('psutil 2.0.0+')
try:
# noinspection PyUnresolvedReferences
import PIL
if tuple(map(int, ('2.5.0'.split(".")))) > tuple(map(int, (PIL.PILLOW_VERSION.split(".")))):
missing.append('Pillow 2.5.0+')
except ImportError:
missing.append('Pillow 2.5.0+')
try:
# noinspection PyUnresolvedReferences
import slugify
except ImportError:
missing.append('python-slugify')
if len(missing) > 0:
try:
# noinspection PyUnresolvedReferences
import tkinter
# noinspection PyUnresolvedReferences
import tkinter.messagebox
importRoot = tkinter.Tk()
importRoot.withdraw()
tkinter.messagebox.showerror('KCC - Error', 'ERROR: ' + ', '.join(missing) + ' is not installed!')
except ImportError:
print('ERROR: ' + ', '.join(missing) + ' is not installed!')
exit(1)
from kcc.shared import dependencyCheck
dependencyCheck(2)
from multiprocessing import freeze_support
from kcc import __version__
from kcc.comic2ebook import main
if __name__ == "__main__":
freeze_support()
print(('comic2ebook v%(__version__)s. Written by Ciro Mattia Gonano and Pawel Jastrzebski.' % globals()))
print('comic2ebook v' + __version__ + ' - Written by Ciro Mattia Gonano and Pawel Jastrzebski.')
main(sys.argv[1:])
sys.exit(0)
sys.exit(0)

View File

@@ -2,7 +2,7 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
# Copyright (c) 2013-2014 Pawel Jastrzebski <pawelj@iosphe.re>
# Copyright (c) 2013-2015 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
@@ -18,43 +18,20 @@
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
__version__ = '4.2.1'
__license__ = 'ISC'
__copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>'
__docformat__ = 'restructuredtext en'
import sys
if sys.version_info[0] != 3:
print('ERROR: This is Python 3 script!')
exit(1)
# Dependency check
missing = []
try:
# noinspection PyUnresolvedReferences
import PIL
if tuple(map(int, ('2.5.0'.split(".")))) > tuple(map(int, (PIL.PILLOW_VERSION.split(".")))):
missing.append('Pillow 2.5.0+')
except ImportError:
missing.append('Pillow 2.5.0+')
if len(missing) > 0:
try:
# noinspection PyUnresolvedReferences
import tkinter
# noinspection PyUnresolvedReferences
import tkinter.messagebox
importRoot = tkinter.Tk()
importRoot.withdraw()
tkinter.messagebox.showerror('KCC - Error', 'ERROR: ' + ', '.join(missing) + ' is not installed!')
except ImportError:
print('ERROR: ' + ', '.join(missing) + ' is not installed!')
exit(1)
from kcc.shared import dependencyCheck
dependencyCheck(1)
from multiprocessing import freeze_support
from kcc import __version__
from kcc.comic2panel import main
if __name__ == "__main__":
freeze_support()
print(('comic2ebook v%(__version__)s. Written by Ciro Mattia Gonano and Pawel Jastrzebski.' % globals()))
print('comic2panel v' + __version__ + ' - Written by Ciro Mattia Gonano and Pawel Jastrzebski.')
main(sys.argv[1:])
sys.exit(0)
sys.exit(0)

52
kcc.iss
View File

@@ -1,5 +1,5 @@
#define MyAppName "Kindle Comic Converter"
#define MyAppVersion "4.2.1"
#define MyAppVersion "4.6.2"
#define MyAppPublisher "Ciro Mattia Gonano, Paweł Jastrzębski"
#define MyAppURL "http://kcc.iosphe.re/"
#define MyAppExeName "KCC.exe"
@@ -12,7 +12,7 @@ AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
AppCopyright=Copyright (C) 2012-2014 Ciro Mattia Gonano and Paweł Jastrzębski
AppCopyright=Copyright (C) 2012-2015 Ciro Mattia Gonano and Paweł Jastrzębski
DefaultDirName={pf}\{#MyAppName}
DefaultGroupName={#MyAppName}
AllowNoIcons=yes
@@ -43,13 +43,11 @@ Name: "CB7association"; Description: "CB7"; GroupDescription: "File associations
[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\{#MyAppExeName}"; 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
; 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\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
Source: "dist\*.dll"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
@@ -87,3 +85,49 @@ Root: HKCR; SubKey: ".cb7"; ValueType: string; ValueData: "KCCCB7"; Flags: unins
Root: HKCR; SubKey: "KCCCB7"; ValueType: string; ValueData: "KCC 7z Archive"; Flags: uninsdeletekey; Tasks: CB7association
Root: HKCR; SubKey: "KCCCB7\Shell\Open\Command"; ValueType: string; ValueData: """{app}\{#MyAppExeName}"" ""%1"""; Flags: uninsdeletekey; Tasks: CB7association
Root: HKCR; Subkey: "KCCCB7\DefaultIcon"; ValueType: string; ValueData: "{app}\{#MyAppExeName},0"; Flags: uninsdeletevalue; Tasks: CB7association
[Code]
function GetUninstallString(): String;
var
sUnInstPath: String;
sUnInstallString: String;
begin
sUnInstPath := ExpandConstant('Software\Microsoft\Windows\CurrentVersion\Uninstall\{#emit SetupSetting("AppId")}_is1');
sUnInstallString := '';
if not RegQueryStringValue(HKLM, sUnInstPath, 'UninstallString', sUnInstallString) then
RegQueryStringValue(HKCU, sUnInstPath, 'UninstallString', sUnInstallString);
Result := sUnInstallString;
end;
function IsUpgrade(): Boolean;
begin
Result := (GetUninstallString() <> '');
end;
function UnInstallOldVersion(): Integer;
var
sUnInstallString: String;
iResultCode: Integer;
begin
Result := 0;
sUnInstallString := GetUninstallString();
if sUnInstallString <> '' then begin
sUnInstallString := RemoveQuotes(sUnInstallString);
if Exec(sUnInstallString, '/SILENT /NORESTART /SUPPRESSMSGBOXES','', SW_HIDE, ewWaitUntilTerminated, iResultCode) then
Result := 3
else
Result := 2;
end else
Result := 1;
end;
procedure CurStepChanged(CurStep: TSetupStep);
begin
if (CurStep=ssInstall) then
begin
if (IsUpgrade()) then
begin
UnInstallOldVersion();
end;
end;
end;

152
kcc.py
View File

@@ -2,7 +2,7 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
# Copyright (c) 2013-2014 Pawel Jastrzebski <pawelj@iosphe.re>
# Copyright (c) 2013-2015 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
@@ -18,166 +18,52 @@
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
__version__ = '4.2.1'
__license__ = 'ISC'
__copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>'
__docformat__ = 'restructuredtext en'
import sys
if sys.version_info[0] != 3:
print('ERROR: This is Python 3 script!')
exit(1)
# Dependency check
missing = []
try:
# noinspection PyUnresolvedReferences
from PyQt5 import QtCore, QtNetwork, QtWidgets
if tuple(map(int, ('5.2.0'.split(".")))) > tuple(map(int, (QtCore.qVersion().split(".")))):
missing.append('PyQt5 5.2.0+')
except ImportError:
missing.append('PyQt5 5.2.0+')
try:
# noinspection PyUnresolvedReferences
import psutil
if tuple(map(int, ('2.0.0'.split(".")))) > tuple(map(int, psutil.version_info)):
missing.append('psutil 2.0.0+')
except ImportError:
missing.append('psutil 2.0.0+')
try:
# noinspection PyUnresolvedReferences
import PIL
if tuple(map(int, ('2.5.0'.split(".")))) > tuple(map(int, (PIL.PILLOW_VERSION.split(".")))):
missing.append('Pillow 2.5.0+')
except ImportError:
missing.append('Pillow 2.5.0+')
try:
# noinspection PyUnresolvedReferences
import slugify
except ImportError:
missing.append('python-slugify')
if len(missing) > 0:
try:
# noinspection PyUnresolvedReferences
import tkinter
# noinspection PyUnresolvedReferences
import tkinter.messagebox
importRoot = tkinter.Tk()
importRoot.withdraw()
tkinter.messagebox.showerror('KCC - Error', 'ERROR: ' + ', '.join(missing) + ' is not installed!')
except ImportError:
print('ERROR: ' + ', '.join(missing) + ' is not installed!')
exit(1)
import os
from multiprocessing import freeze_support
from kcc import KCC_gui
# OS specific PATH variable workarounds
import os
if sys.platform.startswith('darwin'):
if 'RESOURCEPATH' in os.environ:
os.environ['PATH'] = os.environ['RESOURCEPATH'] + ':' + os.environ['PATH']
else:
if 'RESOURCEPATH' not in os.environ:
os.environ['PATH'] = os.path.dirname(os.path.abspath(__file__)) + '/other/:' + os.environ['PATH']
else:
os.environ['PATH'] = './../Resources:/usr/local/bin:/usr/bin:/bin'
elif sys.platform.startswith('win'):
if getattr(sys, 'frozen', False):
os.chdir(os.path.dirname(os.path.abspath(sys.executable)))
# Implementing dummy stdout and stderr for frozen Windows release
class fakestd(object):
class FakeSTD(object):
def write(self, string):
pass
def flush(self):
pass
sys.stdout = fakestd()
sys.stderr = fakestd()
sys.stdout = FakeSTD()
sys.stderr = FakeSTD()
else:
os.environ['PATH'] = os.path.dirname(os.path.abspath(__file__)) + '/other/;' + os.environ['PATH']
os.chdir(os.path.dirname(os.path.abspath(__file__)))
from kcc.shared import dependencyCheck
dependencyCheck(3)
# Implementing detection of already running KCC instance and forwarding argv to it
class QApplicationMessaging(QtWidgets.QApplication):
messageFromOtherInstance = QtCore.pyqtSignal(bytes)
def __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._timeout = 1000
self._server = QtNetwork.QLocalServer(self)
if not self.isRunning():
# noinspection PyUnresolvedReferences
self._server.newConnection.connect(self.handleMessage)
self._server.listen(self._key)
def shutdown(self):
if self._memory.isAttached():
self._memory.detach()
self._server.close()
def event(self, e):
if e.type() == QtCore.QEvent.FileOpen:
# noinspection PyArgumentList
self.messageFromOtherInstance.emit(bytes(e.file(), 'UTF-8'))
return True
else:
return QtWidgets.QApplication.event(self, e)
def isRunning(self):
return self._running
def handleMessage(self):
socket = self._server.nextPendingConnection()
if socket.waitForReadyRead(self._timeout):
self.messageFromOtherInstance.emit(socket.readAll().data())
def sendMessage(self, message):
if self.isRunning():
socket = QtNetwork.QLocalSocket(self)
socket.connectToServer(self._key, QtCore.QIODevice.WriteOnly)
if not socket.waitForConnected(self._timeout):
return False
# noinspection PyArgumentList
socket.write(bytes(message, 'UTF-8'))
if not socket.waitForBytesWritten(self._timeout):
return False
socket.disconnectFromServer()
return True
return False
# Adding signals to QMainWindow
class QMainWindowKCC(QtWidgets.QMainWindow):
progressBarTick = QtCore.pyqtSignal(str)
modeConvert = QtCore.pyqtSignal(int)
addMessage = QtCore.pyqtSignal(str, str, bool)
addTrayMessage = QtCore.pyqtSignal(str, str)
showDialog = QtCore.pyqtSignal(str, str)
hideProgressBar = QtCore.pyqtSignal()
forceShutdown = QtCore.pyqtSignal()
dialogAnswer = QtCore.pyqtSignal(int)
from multiprocessing import freeze_support
from kcc import KCC_gui
if __name__ == "__main__":
freeze_support()
KCCAplication = QApplicationMessaging(sys.argv)
KCCAplication = KCC_gui.QApplicationMessaging(sys.argv)
if KCCAplication.isRunning():
if len(sys.argv) > 1:
KCCAplication.sendMessage(sys.argv[1])
sys.exit(0)
else:
KCCAplication.sendMessage('ARISE')
sys.exit(0)
KCCWindow = QMainWindowKCC()
KCCUI = KCC_gui.KCCGUI(KCCAplication, KCCWindow)
if len(sys.argv) > 1:
KCCUI.handleMessage(sys.argv[1])
sys.exit(KCCAplication.exec_())
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_())

147
kcc/KCC_MetaEditor_ui.py Normal file
View File

@@ -0,0 +1,147 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'MetaEditor.ui'
#
# Created: Sun Feb 8 11:52:00 2015
# by: PyQt5 UI code generator 5.4
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MetaEditorDialog(object):
def setupUi(self, MetaEditorDialog):
MetaEditorDialog.setObjectName("MetaEditorDialog")
MetaEditorDialog.resize(400, 260)
MetaEditorDialog.setMinimumSize(QtCore.QSize(400, 260))
MetaEditorDialog.setMaximumSize(QtCore.QSize(400, 260))
icon = QtGui.QIcon()
icon.addPixmap(QtGui.QPixmap(":/Icon/icons/comic2ebook.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
MetaEditorDialog.setWindowIcon(icon)
self.horizontalLayoutWidget = QtWidgets.QWidget(MetaEditorDialog)
self.horizontalLayoutWidget.setGeometry(QtCore.QRect(10, 220, 381, 31))
self.horizontalLayoutWidget.setObjectName("horizontalLayoutWidget")
self.horizontalLayout = QtWidgets.QHBoxLayout(self.horizontalLayoutWidget)
self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
self.horizontalLayout.setObjectName("horizontalLayout")
self.StatusLabel = QtWidgets.QLabel(self.horizontalLayoutWidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.MinimumExpanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.StatusLabel.sizePolicy().hasHeightForWidth())
self.StatusLabel.setSizePolicy(sizePolicy)
font = QtGui.QFont()
font.setBold(True)
font.setWeight(75)
self.StatusLabel.setFont(font)
self.StatusLabel.setStyleSheet("color: rgb(255, 0, 0);")
self.StatusLabel.setObjectName("StatusLabel")
self.horizontalLayout.addWidget(self.StatusLabel)
self.OKButton = QtWidgets.QPushButton(self.horizontalLayoutWidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.OKButton.sizePolicy().hasHeightForWidth())
self.OKButton.setSizePolicy(sizePolicy)
font = QtGui.QFont()
font.setBold(True)
font.setWeight(75)
self.OKButton.setFont(font)
icon1 = QtGui.QIcon()
icon1.addPixmap(QtGui.QPixmap(":/Other/icons/convert.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.OKButton.setIcon(icon1)
self.OKButton.setObjectName("OKButton")
self.horizontalLayout.addWidget(self.OKButton)
self.CancelButton = QtWidgets.QPushButton(self.horizontalLayoutWidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.CancelButton.sizePolicy().hasHeightForWidth())
self.CancelButton.setSizePolicy(sizePolicy)
font = QtGui.QFont()
font.setBold(True)
font.setWeight(75)
self.CancelButton.setFont(font)
icon2 = QtGui.QIcon()
icon2.addPixmap(QtGui.QPixmap(":/Other/icons/clear.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.CancelButton.setIcon(icon2)
self.CancelButton.setObjectName("CancelButton")
self.horizontalLayout.addWidget(self.CancelButton)
self.EditorFrame = QtWidgets.QFrame(MetaEditorDialog)
self.EditorFrame.setGeometry(QtCore.QRect(10, 10, 381, 211))
self.EditorFrame.setObjectName("EditorFrame")
self.formLayoutWidget = QtWidgets.QWidget(self.EditorFrame)
self.formLayoutWidget.setGeometry(QtCore.QRect(0, 0, 381, 211))
self.formLayoutWidget.setObjectName("formLayoutWidget")
self.formLayout = QtWidgets.QFormLayout(self.formLayoutWidget)
self.formLayout.setContentsMargins(0, 0, 0, 0)
self.formLayout.setObjectName("formLayout")
self.label = QtWidgets.QLabel(self.formLayoutWidget)
self.label.setObjectName("label")
self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.label)
self.SeriesLine = QtWidgets.QLineEdit(self.formLayoutWidget)
self.SeriesLine.setObjectName("SeriesLine")
self.formLayout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.SeriesLine)
self.label_2 = QtWidgets.QLabel(self.formLayoutWidget)
self.label_2.setObjectName("label_2")
self.formLayout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.label_2)
self.VolumeLine = QtWidgets.QLineEdit(self.formLayoutWidget)
self.VolumeLine.setObjectName("VolumeLine")
self.formLayout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.VolumeLine)
self.label_3 = QtWidgets.QLabel(self.formLayoutWidget)
self.label_3.setObjectName("label_3")
self.formLayout.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.label_3)
self.NumberLine = QtWidgets.QLineEdit(self.formLayoutWidget)
self.NumberLine.setObjectName("NumberLine")
self.formLayout.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.NumberLine)
self.label_4 = QtWidgets.QLabel(self.formLayoutWidget)
self.label_4.setObjectName("label_4")
self.formLayout.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.label_4)
self.WriterLine = QtWidgets.QLineEdit(self.formLayoutWidget)
self.WriterLine.setObjectName("WriterLine")
self.formLayout.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.WriterLine)
self.label_5 = QtWidgets.QLabel(self.formLayoutWidget)
self.label_5.setObjectName("label_5")
self.formLayout.setWidget(5, QtWidgets.QFormLayout.LabelRole, self.label_5)
self.PencillerLine = QtWidgets.QLineEdit(self.formLayoutWidget)
self.PencillerLine.setObjectName("PencillerLine")
self.formLayout.setWidget(5, QtWidgets.QFormLayout.FieldRole, self.PencillerLine)
self.label_6 = QtWidgets.QLabel(self.formLayoutWidget)
self.label_6.setObjectName("label_6")
self.formLayout.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.label_6)
self.InkerLine = QtWidgets.QLineEdit(self.formLayoutWidget)
self.InkerLine.setObjectName("InkerLine")
self.formLayout.setWidget(6, QtWidgets.QFormLayout.FieldRole, self.InkerLine)
self.label_7 = QtWidgets.QLabel(self.formLayoutWidget)
self.label_7.setObjectName("label_7")
self.formLayout.setWidget(7, QtWidgets.QFormLayout.LabelRole, self.label_7)
self.ColoristLine = QtWidgets.QLineEdit(self.formLayoutWidget)
self.ColoristLine.setObjectName("ColoristLine")
self.formLayout.setWidget(7, QtWidgets.QFormLayout.FieldRole, self.ColoristLine)
self.label_8 = QtWidgets.QLabel(self.formLayoutWidget)
self.label_8.setTextFormat(QtCore.Qt.RichText)
self.label_8.setOpenExternalLinks(True)
self.label_8.setObjectName("label_8")
self.formLayout.setWidget(8, QtWidgets.QFormLayout.LabelRole, self.label_8)
self.MUidLine = QtWidgets.QLineEdit(self.formLayoutWidget)
self.MUidLine.setObjectName("MUidLine")
self.formLayout.setWidget(8, QtWidgets.QFormLayout.FieldRole, self.MUidLine)
self.retranslateUi(MetaEditorDialog)
QtCore.QMetaObject.connectSlotsByName(MetaEditorDialog)
def retranslateUi(self, MetaEditorDialog):
_translate = QtCore.QCoreApplication.translate
MetaEditorDialog.setWindowTitle(_translate("MetaEditorDialog", "Metadata editor"))
self.OKButton.setText(_translate("MetaEditorDialog", "Save"))
self.CancelButton.setText(_translate("MetaEditorDialog", "Cancel"))
self.label.setText(_translate("MetaEditorDialog", "Series:"))
self.label_2.setText(_translate("MetaEditorDialog", "Volume:"))
self.label_3.setText(_translate("MetaEditorDialog", "Number:"))
self.label_4.setText(_translate("MetaEditorDialog", "Writer:"))
self.label_5.setText(_translate("MetaEditorDialog", "Penciller:"))
self.label_6.setText(_translate("MetaEditorDialog", "Inker:"))
self.label_7.setText(_translate("MetaEditorDialog", "Colorist:"))
self.label_8.setText(_translate("MetaEditorDialog", "<html><head/><body><p><a href=\"https://github.com/ciromattia/kcc/wiki/Manga-Cover-Database-support\"><span style=\" text-decoration: underline; color:#0000ff;\">MUid:</span></a></p></body></html>"))
from . import KCC_rc

View File

@@ -0,0 +1,148 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'gui/MetaEditor.ui'
#
# Created: Sun Feb 8 03:24:23 2015
# by: PyQt5 UI code generator 5.2.1
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MetaEditorDialog(object):
def setupUi(self, MetaEditorDialog):
MetaEditorDialog.setObjectName("MetaEditorDialog")
MetaEditorDialog.resize(400, 320)
MetaEditorDialog.setMinimumSize(QtCore.QSize(400, 320))
MetaEditorDialog.setMaximumSize(QtCore.QSize(400, 320))
icon = QtGui.QIcon()
icon.addPixmap(QtGui.QPixmap(":/Icon/icons/comic2ebook.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
MetaEditorDialog.setWindowIcon(icon)
self.horizontalLayoutWidget = QtWidgets.QWidget(MetaEditorDialog)
self.horizontalLayoutWidget.setGeometry(QtCore.QRect(10, 280, 381, 31))
self.horizontalLayoutWidget.setObjectName("horizontalLayoutWidget")
self.horizontalLayout = QtWidgets.QHBoxLayout(self.horizontalLayoutWidget)
self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
self.horizontalLayout.setObjectName("horizontalLayout")
self.StatusLabel = QtWidgets.QLabel(self.horizontalLayoutWidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.MinimumExpanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.StatusLabel.sizePolicy().hasHeightForWidth())
self.StatusLabel.setSizePolicy(sizePolicy)
font = QtGui.QFont()
font.setPointSize(10)
font.setBold(True)
font.setWeight(75)
self.StatusLabel.setFont(font)
self.StatusLabel.setStyleSheet("color: rgb(255, 0, 0);")
self.StatusLabel.setObjectName("StatusLabel")
self.horizontalLayout.addWidget(self.StatusLabel)
self.OKButton = QtWidgets.QPushButton(self.horizontalLayoutWidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.OKButton.sizePolicy().hasHeightForWidth())
self.OKButton.setSizePolicy(sizePolicy)
font = QtGui.QFont()
font.setBold(True)
font.setWeight(75)
self.OKButton.setFont(font)
icon1 = QtGui.QIcon()
icon1.addPixmap(QtGui.QPixmap(":/Other/icons/convert.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.OKButton.setIcon(icon1)
self.OKButton.setObjectName("OKButton")
self.horizontalLayout.addWidget(self.OKButton)
self.CancelButton = QtWidgets.QPushButton(self.horizontalLayoutWidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.CancelButton.sizePolicy().hasHeightForWidth())
self.CancelButton.setSizePolicy(sizePolicy)
font = QtGui.QFont()
font.setBold(True)
font.setWeight(75)
self.CancelButton.setFont(font)
icon2 = QtGui.QIcon()
icon2.addPixmap(QtGui.QPixmap(":/Other/icons/clear.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.CancelButton.setIcon(icon2)
self.CancelButton.setObjectName("CancelButton")
self.horizontalLayout.addWidget(self.CancelButton)
self.EditorFrame = QtWidgets.QFrame(MetaEditorDialog)
self.EditorFrame.setGeometry(QtCore.QRect(10, 10, 381, 271))
self.EditorFrame.setObjectName("EditorFrame")
self.formLayoutWidget = QtWidgets.QWidget(self.EditorFrame)
self.formLayoutWidget.setGeometry(QtCore.QRect(0, 0, 381, 266))
self.formLayoutWidget.setObjectName("formLayoutWidget")
self.formLayout = QtWidgets.QFormLayout(self.formLayoutWidget)
self.formLayout.setContentsMargins(0, 0, 0, 0)
self.formLayout.setObjectName("formLayout")
self.label = QtWidgets.QLabel(self.formLayoutWidget)
self.label.setObjectName("label")
self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.label)
self.SeriesLine = QtWidgets.QLineEdit(self.formLayoutWidget)
self.SeriesLine.setObjectName("SeriesLine")
self.formLayout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.SeriesLine)
self.label_2 = QtWidgets.QLabel(self.formLayoutWidget)
self.label_2.setObjectName("label_2")
self.formLayout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.label_2)
self.VolumeLine = QtWidgets.QLineEdit(self.formLayoutWidget)
self.VolumeLine.setObjectName("VolumeLine")
self.formLayout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.VolumeLine)
self.label_3 = QtWidgets.QLabel(self.formLayoutWidget)
self.label_3.setObjectName("label_3")
self.formLayout.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.label_3)
self.NumberLine = QtWidgets.QLineEdit(self.formLayoutWidget)
self.NumberLine.setObjectName("NumberLine")
self.formLayout.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.NumberLine)
self.label_4 = QtWidgets.QLabel(self.formLayoutWidget)
self.label_4.setObjectName("label_4")
self.formLayout.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.label_4)
self.WriterLine = QtWidgets.QLineEdit(self.formLayoutWidget)
self.WriterLine.setObjectName("WriterLine")
self.formLayout.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.WriterLine)
self.label_5 = QtWidgets.QLabel(self.formLayoutWidget)
self.label_5.setObjectName("label_5")
self.formLayout.setWidget(5, QtWidgets.QFormLayout.LabelRole, self.label_5)
self.PencillerLine = QtWidgets.QLineEdit(self.formLayoutWidget)
self.PencillerLine.setObjectName("PencillerLine")
self.formLayout.setWidget(5, QtWidgets.QFormLayout.FieldRole, self.PencillerLine)
self.label_6 = QtWidgets.QLabel(self.formLayoutWidget)
self.label_6.setObjectName("label_6")
self.formLayout.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.label_6)
self.InkerLine = QtWidgets.QLineEdit(self.formLayoutWidget)
self.InkerLine.setObjectName("InkerLine")
self.formLayout.setWidget(6, QtWidgets.QFormLayout.FieldRole, self.InkerLine)
self.label_7 = QtWidgets.QLabel(self.formLayoutWidget)
self.label_7.setObjectName("label_7")
self.formLayout.setWidget(7, QtWidgets.QFormLayout.LabelRole, self.label_7)
self.ColoristLine = QtWidgets.QLineEdit(self.formLayoutWidget)
self.ColoristLine.setObjectName("ColoristLine")
self.formLayout.setWidget(7, QtWidgets.QFormLayout.FieldRole, self.ColoristLine)
self.label_8 = QtWidgets.QLabel(self.formLayoutWidget)
self.label_8.setTextFormat(QtCore.Qt.RichText)
self.label_8.setOpenExternalLinks(True)
self.label_8.setObjectName("label_8")
self.formLayout.setWidget(8, QtWidgets.QFormLayout.LabelRole, self.label_8)
self.MUidLine = QtWidgets.QLineEdit(self.formLayoutWidget)
self.MUidLine.setObjectName("MUidLine")
self.formLayout.setWidget(8, QtWidgets.QFormLayout.FieldRole, self.MUidLine)
self.retranslateUi(MetaEditorDialog)
QtCore.QMetaObject.connectSlotsByName(MetaEditorDialog)
def retranslateUi(self, MetaEditorDialog):
_translate = QtCore.QCoreApplication.translate
MetaEditorDialog.setWindowTitle(_translate("MetaEditorDialog", "Metadata editor"))
self.OKButton.setText(_translate("MetaEditorDialog", "Save"))
self.CancelButton.setText(_translate("MetaEditorDialog", "Cancel"))
self.label.setText(_translate("MetaEditorDialog", "Series:"))
self.label_2.setText(_translate("MetaEditorDialog", "Volume:"))
self.label_3.setText(_translate("MetaEditorDialog", "Number:"))
self.label_4.setText(_translate("MetaEditorDialog", "Writer:"))
self.label_5.setText(_translate("MetaEditorDialog", "Penciller:"))
self.label_6.setText(_translate("MetaEditorDialog", "Inker:"))
self.label_7.setText(_translate("MetaEditorDialog", "Colorist:"))
self.label_8.setText(_translate("MetaEditorDialog", "<html><head/><body><p><a href=\"https://github.com/ciromattia/kcc/wiki/Manga-Cover-Database-support\"><span style=\" text-decoration: underline; color:#0000ff;\">MUid:</span></a></p></body></html>"))
from . import KCC_rc

View File

@@ -0,0 +1,148 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file '/Users/pawelj/Documents/KCC/gui/MetaEditor.ui'
#
# Created: Sun Feb 8 12:47:09 2015
# by: PyQt5 UI code generator 5.4
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MetaEditorDialog(object):
def setupUi(self, MetaEditorDialog):
MetaEditorDialog.setObjectName("MetaEditorDialog")
MetaEditorDialog.resize(400, 295)
MetaEditorDialog.setMinimumSize(QtCore.QSize(400, 295))
MetaEditorDialog.setMaximumSize(QtCore.QSize(400, 295))
icon = QtGui.QIcon()
icon.addPixmap(QtGui.QPixmap(":/Icon/icons/comic2ebook.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
MetaEditorDialog.setWindowIcon(icon)
self.horizontalLayoutWidget = QtWidgets.QWidget(MetaEditorDialog)
self.horizontalLayoutWidget.setGeometry(QtCore.QRect(10, 260, 381, 32))
self.horizontalLayoutWidget.setObjectName("horizontalLayoutWidget")
self.horizontalLayout = QtWidgets.QHBoxLayout(self.horizontalLayoutWidget)
self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
self.horizontalLayout.setObjectName("horizontalLayout")
self.StatusLabel = QtWidgets.QLabel(self.horizontalLayoutWidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.MinimumExpanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.StatusLabel.sizePolicy().hasHeightForWidth())
self.StatusLabel.setSizePolicy(sizePolicy)
font = QtGui.QFont()
font.setPointSize(10)
font.setBold(True)
font.setWeight(75)
self.StatusLabel.setFont(font)
self.StatusLabel.setStyleSheet("color: rgb(255, 0, 0);")
self.StatusLabel.setObjectName("StatusLabel")
self.horizontalLayout.addWidget(self.StatusLabel)
self.OKButton = QtWidgets.QPushButton(self.horizontalLayoutWidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.OKButton.sizePolicy().hasHeightForWidth())
self.OKButton.setSizePolicy(sizePolicy)
font = QtGui.QFont()
font.setBold(True)
font.setWeight(75)
self.OKButton.setFont(font)
icon1 = QtGui.QIcon()
icon1.addPixmap(QtGui.QPixmap(":/Other/icons/convert.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.OKButton.setIcon(icon1)
self.OKButton.setObjectName("OKButton")
self.horizontalLayout.addWidget(self.OKButton)
self.CancelButton = QtWidgets.QPushButton(self.horizontalLayoutWidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.CancelButton.sizePolicy().hasHeightForWidth())
self.CancelButton.setSizePolicy(sizePolicy)
font = QtGui.QFont()
font.setBold(True)
font.setWeight(75)
self.CancelButton.setFont(font)
icon2 = QtGui.QIcon()
icon2.addPixmap(QtGui.QPixmap(":/Other/icons/clear.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.CancelButton.setIcon(icon2)
self.CancelButton.setObjectName("CancelButton")
self.horizontalLayout.addWidget(self.CancelButton)
self.EditorFrame = QtWidgets.QFrame(MetaEditorDialog)
self.EditorFrame.setGeometry(QtCore.QRect(10, 10, 381, 251))
self.EditorFrame.setObjectName("EditorFrame")
self.formLayoutWidget = QtWidgets.QWidget(self.EditorFrame)
self.formLayoutWidget.setGeometry(QtCore.QRect(0, 0, 381, 250))
self.formLayoutWidget.setObjectName("formLayoutWidget")
self.formLayout = QtWidgets.QFormLayout(self.formLayoutWidget)
self.formLayout.setContentsMargins(0, 0, 0, 0)
self.formLayout.setObjectName("formLayout")
self.label = QtWidgets.QLabel(self.formLayoutWidget)
self.label.setObjectName("label")
self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.label)
self.SeriesLine = QtWidgets.QLineEdit(self.formLayoutWidget)
self.SeriesLine.setObjectName("SeriesLine")
self.formLayout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.SeriesLine)
self.label_2 = QtWidgets.QLabel(self.formLayoutWidget)
self.label_2.setObjectName("label_2")
self.formLayout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.label_2)
self.VolumeLine = QtWidgets.QLineEdit(self.formLayoutWidget)
self.VolumeLine.setObjectName("VolumeLine")
self.formLayout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.VolumeLine)
self.label_3 = QtWidgets.QLabel(self.formLayoutWidget)
self.label_3.setObjectName("label_3")
self.formLayout.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.label_3)
self.NumberLine = QtWidgets.QLineEdit(self.formLayoutWidget)
self.NumberLine.setObjectName("NumberLine")
self.formLayout.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.NumberLine)
self.label_4 = QtWidgets.QLabel(self.formLayoutWidget)
self.label_4.setObjectName("label_4")
self.formLayout.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.label_4)
self.WriterLine = QtWidgets.QLineEdit(self.formLayoutWidget)
self.WriterLine.setObjectName("WriterLine")
self.formLayout.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.WriterLine)
self.label_5 = QtWidgets.QLabel(self.formLayoutWidget)
self.label_5.setObjectName("label_5")
self.formLayout.setWidget(5, QtWidgets.QFormLayout.LabelRole, self.label_5)
self.PencillerLine = QtWidgets.QLineEdit(self.formLayoutWidget)
self.PencillerLine.setObjectName("PencillerLine")
self.formLayout.setWidget(5, QtWidgets.QFormLayout.FieldRole, self.PencillerLine)
self.label_6 = QtWidgets.QLabel(self.formLayoutWidget)
self.label_6.setObjectName("label_6")
self.formLayout.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.label_6)
self.InkerLine = QtWidgets.QLineEdit(self.formLayoutWidget)
self.InkerLine.setObjectName("InkerLine")
self.formLayout.setWidget(6, QtWidgets.QFormLayout.FieldRole, self.InkerLine)
self.label_7 = QtWidgets.QLabel(self.formLayoutWidget)
self.label_7.setObjectName("label_7")
self.formLayout.setWidget(7, QtWidgets.QFormLayout.LabelRole, self.label_7)
self.ColoristLine = QtWidgets.QLineEdit(self.formLayoutWidget)
self.ColoristLine.setObjectName("ColoristLine")
self.formLayout.setWidget(7, QtWidgets.QFormLayout.FieldRole, self.ColoristLine)
self.label_8 = QtWidgets.QLabel(self.formLayoutWidget)
self.label_8.setTextFormat(QtCore.Qt.RichText)
self.label_8.setOpenExternalLinks(True)
self.label_8.setObjectName("label_8")
self.formLayout.setWidget(8, QtWidgets.QFormLayout.LabelRole, self.label_8)
self.MUidLine = QtWidgets.QLineEdit(self.formLayoutWidget)
self.MUidLine.setObjectName("MUidLine")
self.formLayout.setWidget(8, QtWidgets.QFormLayout.FieldRole, self.MUidLine)
self.retranslateUi(MetaEditorDialog)
QtCore.QMetaObject.connectSlotsByName(MetaEditorDialog)
def retranslateUi(self, MetaEditorDialog):
_translate = QtCore.QCoreApplication.translate
MetaEditorDialog.setWindowTitle(_translate("MetaEditorDialog", "Metadata editor"))
self.OKButton.setText(_translate("MetaEditorDialog", "Save"))
self.CancelButton.setText(_translate("MetaEditorDialog", "Cancel"))
self.label.setText(_translate("MetaEditorDialog", "Series:"))
self.label_2.setText(_translate("MetaEditorDialog", "Volume:"))
self.label_3.setText(_translate("MetaEditorDialog", "Number:"))
self.label_4.setText(_translate("MetaEditorDialog", "Writer:"))
self.label_5.setText(_translate("MetaEditorDialog", "Penciller:"))
self.label_6.setText(_translate("MetaEditorDialog", "Inker:"))
self.label_7.setText(_translate("MetaEditorDialog", "Colorist:"))
self.label_8.setText(_translate("MetaEditorDialog", "<html><head/><body><p><a href=\"https://github.com/ciromattia/kcc/wiki/Manga-Cover-Database-support\"><span style=\" text-decoration: underline; color:#0000ff;\">MUid:</span></a></p></body></html>"))
from . import KCC_rc

View File

@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
# Copyright (c) 2013-2014 Pawel Jastrzebski <pawelj@iosphe.re>
# Copyright (c) 2013-2015 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
@@ -17,11 +17,6 @@
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
__version__ = '4.2.1'
__license__ = 'ISC'
__copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>'
__docformat__ = 'restructuredtext en'
import os
import sys
from urllib.parse import unquote
@@ -33,22 +28,86 @@ from shutil import move
from http.server import BaseHTTPRequestHandler, HTTPServer
from socketserver import ThreadingMixIn
from subprocess import STDOUT, PIPE
from PyQt5 import QtGui, QtCore, QtWidgets
from PyQt5 import QtGui, QtCore, QtWidgets, QtNetwork
from xml.dom.minidom import parse
from html.parser import HTMLParser
from psutil import virtual_memory, Popen, Process
from uuid import uuid4
from psutil import Popen, Process
from copy import copy
from .shared import md5Checksum
from distutils.version import StrictVersion
from xml.sax.saxutils import escape
from .shared import md5Checksum, HTMLStripper
from . import __version__
from . import comic2ebook
from . import dualmetafix
from . import KCC_rc_web
from . import metadata
if sys.platform.startswith('darwin'):
from . import KCC_ui_osx as KCC_ui
elif sys.platform.startswith('linux'):
from . import KCC_ui_linux as KCC_ui
else:
from . import KCC_ui
if sys.platform.startswith('darwin'):
from . import KCC_MetaEditor_ui_osx as KCC_MetaEditor_ui
elif sys.platform.startswith('linux'):
from . import KCC_MetaEditor_ui_linux as KCC_MetaEditor_ui
else:
from . import KCC_MetaEditor_ui
class QApplicationMessaging(QtWidgets.QApplication):
messageFromOtherInstance = QtCore.pyqtSignal(bytes)
def __init__(self, argv):
QtWidgets.QApplication.__init__(self, argv)
self._key = 'KCC'
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)
# noinspection PyUnresolvedReferences
self._server.newConnection.connect(self.handleMessage)
self._server.listen(self._key)
else:
self._locked = True
socket.disconnectFromServer()
def __del__(self):
if not self._locked:
self._server.close()
def event(self, e):
if e.type() == QtCore.QEvent.FileOpen:
self.messageFromOtherInstance.emit(bytes(e.file(), 'UTF-8'))
return True
else:
return QtWidgets.QApplication.event(self, e)
def isRunning(self):
return self._locked
def handleMessage(self):
socket = self._server.nextPendingConnection()
if socket.waitForReadyRead(self._timeout):
self.messageFromOtherInstance.emit(socket.readAll().data())
def sendMessage(self, message):
socket = QtNetwork.QLocalSocket(self)
socket.connectToServer(self._key, QtCore.QIODevice.WriteOnly)
socket.waitForConnected(self._timeout)
socket.write(bytes(message, 'UTF-8'))
socket.waitForBytesWritten(self._timeout)
socket.disconnectFromServer()
class QMainWindowKCC(QtWidgets.QMainWindow):
progressBarTick = QtCore.pyqtSignal(str)
modeConvert = QtCore.pyqtSignal(int)
addMessage = QtCore.pyqtSignal(str, str, bool)
addTrayMessage = QtCore.pyqtSignal(str, str)
showDialog = QtCore.pyqtSignal(str, str)
hideProgressBar = QtCore.pyqtSignal()
forceShutdown = QtCore.pyqtSignal()
class Icons:
@@ -78,19 +137,6 @@ class Icons:
self.programIcon.addPixmap(QtGui.QPixmap(":/Icon/icons/comic2ebook.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
class HTMLStripper(HTMLParser):
def __init__(self):
HTMLParser.__init__(self)
self.reset()
self.fed = []
def handle_data(self, d):
self.fed.append(d)
def get_data(self):
return ''.join(self.fed)
class WebServerHandler(BaseHTTPRequestHandler):
# noinspection PyAttributeOutsideInit, PyArgumentList
def do_GET(self):
@@ -113,15 +159,15 @@ class WebServerHandler(BaseHTTPRequestHandler):
self.send_header('Content-type', 'text/html')
self.end_headers()
self.wfile.write(bytes('<!DOCTYPE html>\n'
'<html lang="en">\n'
'<head><meta charset="utf-8">\n'
'<link href="' + GUI.webContent.favicon + '" rel="icon" type="image/x-icon" />\n'
'<title>Kindle Comic Converter</title>\n'
'</head>\n'
'<body>\n'
'<div style="text-align: center; font-size:25px">\n'
'<p style="font-size:50px">- <img style="vertical-align: middle" '
'alt="KCC Logo" src="' + GUI.webContent.logo + '" /> -</p>\n', 'UTF-8'))
'<html lang="en">\n'
'<head><meta charset="utf-8">\n'
'<link href="' + GUI.webContent.favicon + '" rel="icon" type="image/x-icon" />\n'
'<title>Kindle Comic Converter</title>\n'
'</head>\n'
'<body>\n'
'<div style="text-align: center; font-size:25px">\n'
'<p style="font-size:50px">- <img style="vertical-align: middle" '
'alt="KCC Logo" src="' + GUI.webContent.logo + '" /> -</p>\n', 'UTF-8'))
if len(GUI.completedWork) > 0 and not GUI.conversionAlive:
for key in sorted(GUI.completedWork.keys()):
self.wfile.write(bytes('<p><a href="' + key + '">' + key.split('.')[0] + '</a></p>\n', 'UTF-8'))
@@ -129,8 +175,8 @@ class WebServerHandler(BaseHTTPRequestHandler):
self.wfile.write(bytes('<p style="font-weight: bold">No downloads are available.<br/>'
'Convert some files and refresh this page.</p>\n', 'UTF-8'))
self.wfile.write(bytes('</div>\n'
'</body>\n'
'</html>\n', 'UTF-8'))
'</body>\n'
'</html>\n', 'UTF-8'))
elif sendReply:
outputFile = GUI.completedWork[unquote(self.path[1:])]
fp = open(outputFile, 'rb')
@@ -191,6 +237,8 @@ class VersionThread(QtCore.QThread):
QtCore.QThread.__init__(self)
self.newVersion = ''
self.md5 = ''
self.barProgress = 0
self.answer = None
def __del__(self):
self.wait()
@@ -202,22 +250,28 @@ class VersionThread(QtCore.QThread):
except Exception:
return
latestVersion = XML.childNodes[0].getElementsByTagName('latest')[0].childNodes[0].toxml()
if tuple(map(int, (latestVersion.split(".")))) > tuple(map(int, (__version__.split(".")))):
if StrictVersion(latestVersion) > StrictVersion(__version__):
if sys.platform.startswith('win'):
self.newVersion = latestVersion
self.md5 = XML.childNodes[0].getElementsByTagName('WindowsMD5')[0].childNodes[0].toxml()
MW.showDialog.emit('<b>New version released!</b> <a href="https://github.com/ciromattia/kcc/releases/">'
'See changelog.</a><<br/><br/>Installed version: ' + __version__ +
'See changelog.</a><br/><br/>Installed version: ' + __version__ +
'<br/>Current version: ' + latestVersion +
'<br/><br/>Would you like to start automatic update?', 'question')
self.getNewVersion()
else:
MW.addMessage.emit('<a href="http://kcc.iosphe.re/">'
'<b>New version is available!</b></a> '
'(<a href="https://github.com/ciromattia/kcc/releases/">'
'Changelog</a>)', 'warning', False)
def getNewVersion(self, dialogAnswer):
if dialogAnswer == QtWidgets.QMessageBox.Yes:
def setAnswer(self, dialogAnswer):
self.answer = dialogAnswer
def getNewVersion(self):
while self.answer is None:
sleep(1)
if self.answer == QtWidgets.QMessageBox.Yes:
try:
MW.modeConvert.emit(-1)
MW.progressBarTick.emit('Downloading update')
@@ -236,9 +290,12 @@ class VersionThread(QtCore.QThread):
MW.modeConvert.emit(1)
def getNewVersionTick(self, size, blockSize, totalSize):
progress = int((size / (totalSize // blockSize)) * 100)
if size == 0:
MW.progressBarTick.emit(str(int(totalSize / blockSize)))
MW.progressBarTick.emit('tick')
MW.progressBarTick.emit('100')
if progress > self.barProgress:
self.barProgress = progress
MW.progressBarTick.emit('tick')
class ProgressThread(QtCore.QThread):
@@ -265,84 +322,14 @@ class ProgressThread(QtCore.QThread):
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):
#noinspection PyArgumentList
# noinspection PyArgumentList
def __init__(self):
QtCore.QThread.__init__(self)
self.pool = QtCore.QThreadPool()
self.conversionAlive = False
self.errors = False
self.kindlegenErrorCode = [0]
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.addMessage = MW.addMessage
@@ -361,9 +348,11 @@ class WorkerThread(QtCore.QThread):
MW.addTrayMessage.emit('Conversion interrupted.', 'Critical')
MW.modeConvert.emit(1)
def addResult(self, output):
MW.progressBarTick.emit('tick')
self.workerOutput.append(output)
def sanitizeTrace(self, traceback):
return ''.join(format_tb(traceback))\
.replace('C:\\Users\\AcidWeb\\Documents\\Projekty\\KCC\\', '')\
.replace('C:\\Python34\\', '')\
.replace('C:\\Python34_64\\', '')
def run(self):
MW.modeConvert.emit(0)
@@ -385,11 +374,7 @@ class WorkerThread(QtCore.QThread):
options.quality = 1
elif GUI.QualityBox.checkState() == 2:
options.quality = 2
if str(GUI.FormatBox.currentText()) == 'CBZ':
options.cbzoutput = True
if GUI.currentMode == 1:
if profile in ['KFHD', 'KFHD8', 'KFHDX', 'KFHDX8']:
options.upscale = True
options.format = str(GUI.FormatBox.currentText())
# Advanced mode settings
if GUI.currentMode > 1:
@@ -410,10 +395,7 @@ class WorkerThread(QtCore.QThread):
if GUI.WebtoonBox.isChecked():
options.webtoon = True
if float(GUI.GammaValue) > 0.09:
# noinspection PyTypeChecker
options.gamma = float(GUI.GammaValue)
if str(GUI.FormatBox.currentText()) == 'MOBI':
options.batchsplit = True
# Other/custom settings.
if GUI.currentMode > 2:
@@ -462,7 +444,7 @@ class WorkerThread(QtCore.QThread):
self.errors = True
_, _, traceback = sys.exc_info()
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.addTrayMessage.emit('Failed to create EPUB!', 'Critical')
if not self.conversionAlive:
@@ -483,16 +465,10 @@ class WorkerThread(QtCore.QThread):
MW.progressBarTick.emit('tick')
MW.addMessage.emit('Creating MOBI files', 'info', False)
GUI.progress.content = 'Creating MOBI files'
self.workerOutput = []
# Number of KindleGen threads depends on the size of RAM
self.pool.setMaxThreadCount(self.threadNumber)
work = []
for item in outputPath:
worker = KindleGenThread(item)
worker.signals.result.connect(self.addResult)
self.pool.start(worker)
self.pool.waitForDone()
while len(self.workerOutput) != len(outputPath):
sleep(0.1)
work.append([item])
self.workerOutput = comic2ebook.makeMOBI(work, self)
self.kindlegenErrorCode = [0]
for errors in self.workerOutput:
if errors[0] != 0:
@@ -512,15 +488,9 @@ class WorkerThread(QtCore.QThread):
MW.addMessage.emit('Processing MOBI files', 'info', False)
GUI.progress.content = 'Processing MOBI files'
self.workerOutput = []
# DualMetaFix is very fast and there is not reason to use multithreading.
self.pool.setMaxThreadCount(1)
for item in outputPath:
worker = DualMetaFixThread(item)
worker.signals.result.connect(self.addResult)
self.pool.start(worker)
self.pool.waitForDone()
while len(self.workerOutput) != len(outputPath):
sleep(0.1)
self.workerOutput.append(comic2ebook.makeMOBIFix(item))
MW.progressBarTick.emit('tick')
for success in self.workerOutput:
if not success[0]:
self.errors = True
@@ -584,6 +554,7 @@ class WorkerThread(QtCore.QThread):
class SystemTrayIcon(QtWidgets.QSystemTrayIcon):
def __init__(self):
super().__init__()
if self.isSystemTrayAvailable():
QtWidgets.QSystemTrayIcon.__init__(self, GUI.icons.programIcon, MW)
# noinspection PyUnresolvedReferences
@@ -611,6 +582,7 @@ class KCCGUI(KCC_ui.Ui_KCC):
dname = dname.replace('/', '\\')
self.lastPath = os.path.abspath(os.path.join(dname, os.pardir))
GUI.JobList.addItem(dname)
GUI.JobList.scrollToBottom()
def selectFile(self):
if self.needClean:
@@ -636,6 +608,35 @@ class KCCGUI(KCC_ui.Ui_KCC):
fname = fname.replace('/', '\\')
self.lastPath = os.path.abspath(os.path.join(fname, os.pardir))
GUI.JobList.addItem(fname)
GUI.JobList.scrollToBottom()
def selectFileMetaEditor(self):
if self.UnRAR:
if self.sevenza:
fname = QtWidgets.QFileDialog.getOpenFileName(MW, 'Select file', self.lastPath,
'Comic (*.cbz *.cbr *.cb7)')
else:
fname = QtWidgets.QFileDialog.getOpenFileName(MW, 'Select file', self.lastPath,
'Comic (*.cbz *.cbr)')
else:
if self.sevenza:
fname = QtWidgets.QFileDialog.getOpenFileName(MW, 'Select file', self.lastPath,
'Comic (*.cbz *.cb7)')
else:
fname = QtWidgets.QFileDialog.getOpenFileName(MW, 'Select file', self.lastPath,
'Comic (*.cbz)')
if fname[0] != '':
if sys.platform.startswith('win'):
fname = fname[0].replace('/', '\\')
else:
fname = fname[0]
self.lastPath = os.path.abspath(os.path.join(fname, os.pardir))
try:
self.editor.loadData(fname)
except:
self.showDialog('Failed to parse metadata!', 'error')
else:
self.editor.ui.exec_()
def clearJobs(self):
GUI.JobList.clear()
@@ -651,6 +652,7 @@ class KCCGUI(KCC_ui.Ui_KCC):
MW.setMinimumSize(QtCore.QSize(420, 287))
MW.resize(420, 287)
GUI.BasicModeButton.setEnabled(True)
GUI.EditorButton.setEnabled(True)
GUI.AdvModeButton.setEnabled(True)
GUI.BasicModeButton.setStyleSheet('font-weight:Bold;')
GUI.AdvModeButton.setStyleSheet('font-weight:Normal;')
@@ -680,6 +682,7 @@ class KCCGUI(KCC_ui.Ui_KCC):
MW.setMinimumSize(QtCore.QSize(420, 365))
MW.resize(420, 365)
GUI.BasicModeButton.setEnabled(True)
GUI.EditorButton.setEnabled(True)
GUI.AdvModeButton.setEnabled(True)
GUI.BasicModeButton.setStyleSheet('font-weight:Normal;')
GUI.AdvModeButton.setStyleSheet('font-weight:Bold;')
@@ -709,6 +712,7 @@ class KCCGUI(KCC_ui.Ui_KCC):
MW.setMinimumSize(QtCore.QSize(420, 397))
MW.resize(420, 397)
GUI.BasicModeButton.setEnabled(False)
GUI.EditorButton.setEnabled(True)
GUI.AdvModeButton.setEnabled(False)
GUI.BasicModeButton.setStyleSheet('font-weight:Normal;')
GUI.AdvModeButton.setStyleSheet('font-weight:Normal;')
@@ -739,6 +743,7 @@ class KCCGUI(KCC_ui.Ui_KCC):
status = True
if self.currentMode != 3:
GUI.BasicModeButton.setEnabled(status)
GUI.EditorButton.setEnabled(status)
GUI.AdvModeButton.setEnabled(status)
if self.currentMode != 1:
GUI.FormatBox.setEnabled(status)
@@ -924,9 +929,9 @@ class KCCGUI(KCC_ui.Ui_KCC):
if kind == 'error':
QtWidgets.QMessageBox.critical(MW, 'KCC - Error', message, QtWidgets.QMessageBox.Ok)
elif kind == 'question':
dialogResponse = QtWidgets.QMessageBox.question(MW, 'KCC - Question', message,
QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No)
MW.dialogAnswer.emit(dialogResponse)
GUI.versionCheck.setAnswer(QtWidgets.QMessageBox.question(MW, 'KCC - Question', message,
QtWidgets.QMessageBox.Yes,
QtWidgets.QMessageBox.No))
def updateProgressbar(self, command):
if command == 'tick':
@@ -934,6 +939,7 @@ class KCCGUI(KCC_ui.Ui_KCC):
elif command.isdigit():
GUI.ProgressBar.setMaximum(int(command) - 1)
GUI.BasicModeButton.hide()
GUI.EditorButton.hide()
GUI.AdvModeButton.hide()
GUI.ProgressBar.reset()
GUI.ProgressBar.show()
@@ -971,20 +977,25 @@ class KCCGUI(KCC_ui.Ui_KCC):
self.addMessage('Target resolution is not set!', 'error')
self.needClean = True
return
if str(GUI.FormatBox.currentText()) == 'MOBI' and not GUI.KindleGen:
self.addMessage('Cannot find <a href="http://www.amazon.com/gp/feature.html?ie=UTF8&docId=1000765211">'
'<b>KindleGen</b></a>! MOBI conversion is not possible!', 'error')
if sys.platform.startswith('win'):
self.addMessage('Download it and place EXE in KCC directory.', 'error')
else:
self.addMessage('Download it, and place executable in /usr/local/bin directory.', 'error')
self.needClean = True
return
if str(GUI.FormatBox.currentText()) == 'MOBI' and not self.KindleGen:
self.detectKindleGen()
if not self.KindleGen:
GUI.JobList.clear()
self.addMessage('Cannot find <a href="http://www.amazon.com/gp/feature.html'
'?ie=UTF8&docId=1000765211"><b>KindleGen</b></a>!'
' MOBI conversion is unavailable!', 'error')
if sys.platform.startswith('win'):
self.addMessage('Download it and place EXE in KCC directory.', 'error')
else:
self.addMessage('Download it and place executable in /usr/local/bin directory.', 'error')
self.needClean = True
return
self.worker.start()
def hideProgressBar(self):
GUI.ProgressBar.hide()
GUI.BasicModeButton.show()
GUI.EditorButton.show()
GUI.AdvModeButton.show()
def saveSettings(self, event):
@@ -1018,7 +1029,6 @@ class KCCGUI(KCC_ui.Ui_KCC):
'GammaSlider': float(self.GammaValue)*100})
self.settings.sync()
self.tray.hide()
APP.shutdown()
def handleMessage(self, message):
MW.raise_()
@@ -1041,10 +1051,12 @@ class KCCGUI(KCC_ui.Ui_KCC):
formats = ['.cbz', '.zip', '.pdf']
if os.path.isdir(message):
GUI.JobList.addItem(message)
GUI.JobList.scrollToBottom()
elif os.path.isfile(message):
extension = os.path.splitext(message)
if extension[1].lower() in formats:
GUI.JobList.addItem(message)
GUI.JobList.scrollToBottom()
else:
self.addMessage('This file type is unsupported!', 'error')
@@ -1066,6 +1078,34 @@ class KCCGUI(KCC_ui.Ui_KCC):
self.saveSettings(None)
sys.exit(0)
def detectKindleGen(self, startup=False):
if not sys.platform.startswith('win'):
try:
os.chmod('/usr/local/bin/kindlegen', 0o755)
except Exception:
pass
kindleGenExitCode = Popen('kindlegen -locale en', stdout=PIPE, stderr=STDOUT, shell=True)
if kindleGenExitCode.wait() == 0:
self.KindleGen = True
versionCheck = Popen('kindlegen -locale en', stdout=PIPE, stderr=STDOUT, shell=True)
for line in versionCheck.stdout:
line = line.decode("utf-8")
if 'Amazon kindlegen' in line:
versionCheck = line.split('V')[1].split(' ')[0]
if StrictVersion(versionCheck) < StrictVersion('2.9'):
self.addMessage('Your <a href="http://www.amazon.com/gp/feature.html?ie=UTF8&docId='
'1000765211">KindleGen</a> is outdated! MOBI conversion might fail.', 'warning')
break
else:
self.KindleGen = False
if startup:
self.addMessage('Cannot find <a href="http://www.amazon.com/gp/feature.html?ie=UTF8&docId=1000765211">'
'<b>KindleGen</b></a>! MOBI conversion will be unavailable!', 'error')
if sys.platform.startswith('win'):
self.addMessage('Download it and place EXE in KCC directory.', 'error')
else:
self.addMessage('Download it and place executable in /usr/local/bin directory.', 'error')
# noinspection PyArgumentList
def __init__(self, KCCAplication, KCCWindow):
global APP, MW, GUI
@@ -1073,16 +1113,11 @@ class KCCGUI(KCC_ui.Ui_KCC):
MW = KCCWindow
GUI = self
self.setupUi(MW)
# User settings will be reverted to default ones if were created in one of the following versions
# Empty string cover all versions before this system was implemented
purgeSettingsVersions = ['']
self.editor = KCCGUI_MetaEditor()
self.icons = Icons()
self.webContent = KCC_rc_web.WebContent()
self.settings = QtCore.QSettings('KindleComicConverter', 'KindleComicConverter')
self.settingsVersion = self.settings.value('settingsVersion', '', type=str)
if self.settingsVersion in purgeSettingsVersions:
QtCore.QSettings.clear(self.settings)
self.settingsVersion = self.settings.value('settingsVersion', '', type=str)
self.lastPath = self.settings.value('lastPath', '', type=str)
self.lastDevice = self.settings.value('lastDevice', 0, type=int)
self.currentMode = self.settings.value('currentMode', 1, type=int)
@@ -1096,6 +1131,7 @@ class KCCGUI(KCC_ui.Ui_KCC):
self.tray = SystemTrayIcon()
self.conversionAlive = False
self.needClean = True
self.KindleGen = False
self.GammaValue = 1.0
self.completedWork = {}
self.targetDirectory = ''
@@ -1103,11 +1139,13 @@ class KCCGUI(KCC_ui.Ui_KCC):
self.listFontSize = 11
self.statusBarFontSize = 10
self.statusBarStyle = 'QLabel{padding-top:2px;padding-bottom:3px;}'
self.ProgressBar.setStyleSheet('QProgressBar{padding-top:5px;text-align:center;}')
self.ProgressBar.setStyleSheet('QProgressBar{font-size:13px;text-align:center;'
'border:2px solid grey;border-radius:5px;}'
'QProgressBar::chunk{background-color:steelblue;width:20px;}')
elif sys.platform.startswith('linux'):
self.listFontSize = 8
self.statusBarFontSize = 8
self.statusBarStyle = 'QLabel{padding-top:5px;padding-bottom:3px;}'
self.statusBarStyle = 'QLabel{padding-top:3px;padding-bottom:3px;}'
self.statusBar.setStyleSheet('QStatusBar::item{border:0px;border-top:2px solid #C2C7CB;}')
else:
self.listFontSize = 9
@@ -1121,60 +1159,50 @@ class KCCGUI(KCC_ui.Ui_KCC):
self.p.ionice(1)
self.profiles = {
"Kindle Paperwhite": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 0,
'DefaultUpscale': False, 'Label': 'KHD'},
"K. PW 3/Voyage": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 0,
'DefaultUpscale': False, 'Label': 'KV'},
"Kindle PW 1/2": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 0,
'DefaultUpscale': False, 'Label': 'KPW'},
"Kindle": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 0,
'DefaultUpscale': False, 'Label': 'K345'},
"Kindle DX/DXG": {'Quality': False, 'ForceExpert': False, 'DefaultFormat': 2,
'DefaultUpscale': False, 'Label': 'KDX'},
"Kindle Fire": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 0,
'DefaultUpscale': False, 'Label': 'KF'},
"K. Fire HD 7\"": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 0,
'DefaultUpscale': True, 'Label': 'KFHD'},
"K. Fire HD 8.9\"": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 0,
'DefaultUpscale': True, 'Label': 'KFHD8'},
"K. Fire HDX 7\"": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 0,
'DefaultUpscale': True, 'Label': 'KFHDX'},
"K. Fire HDX 8.9\"": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 0,
'DefaultUpscale': True, 'Label': 'KFHDX8'},
"Kobo Mini/Touch": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 2,
"Kobo Mini/Touch": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 1,
'DefaultUpscale': False, 'Label': 'KoMT'},
"Kobo Glow": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 2,
'DefaultUpscale': False, 'Label': 'KoG'},
"Kobo Aura": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 2,
"Kobo Glo": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 1,
'DefaultUpscale': False, 'Label': 'KoG'},
"Kobo Glo HD": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 1,
'DefaultUpscale': False, 'Label': 'KoGHD'},
"Kobo Aura": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 1,
'DefaultUpscale': False, 'Label': 'KoA'},
"Kobo Aura HD": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 2,
"Kobo Aura HD": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 1,
'DefaultUpscale': False, 'Label': 'KoAHD'},
"Kobo Aura H2O": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 1,
'DefaultUpscale': False, 'Label': 'KoAH2O'},
"Other": {'Quality': False, 'ForceExpert': True, 'DefaultFormat': 1,
'DefaultUpscale': False, 'Label': 'OTHER'},
"Kindle for Android": {'Quality': False, 'ForceExpert': True, 'DefaultFormat': 0,
'DefaultUpscale': False, 'Label': 'KFA'},
"Kindle 1": {'Quality': False, 'ForceExpert': False, 'DefaultFormat': 0,
'DefaultUpscale': False, 'Label': 'K1'},
"Kindle 2": {'Quality': False, 'ForceExpert': False, 'DefaultFormat': 0,
'DefaultUpscale': False, 'Label': 'K2'}
}
profilesGUI = [
"Kindle Paperwhite",
"K. PW 3/Voyage",
"Kindle PW 1/2",
"Kindle",
"Kindle DX/DXG",
"Separator",
"Kindle Fire",
"K. Fire HD 7\"",
"K. Fire HD 8.9\"",
"K. Fire HDX 7\"",
"K. Fire HDX 8.9\"",
"Separator",
"Kobo Mini/Touch",
"Kobo Glow",
"Kobo Glo",
"Kobo Glo HD",
"Kobo Aura",
"Kobo Aura HD",
"Kobo Aura H2O",
"Separator",
"Other",
"Separator",
"Kindle for Android",
"Kindle 1",
"Kindle 2",
"Kindle DX/DXG",
]
statusBarLabel = QtWidgets.QLabel('<b><a href="http://kcc.iosphe.re/">HOMEPAGE</a> - <a href="https://github.'
@@ -1195,27 +1223,6 @@ class KCCGUI(KCC_ui.Ui_KCC):
self.addMessage('Since you are new user of <b>KCC</b> please see few '
'<a href="https://github.com/ciromattia/kcc/wiki/Important-tips">important tips</a>.',
'info')
if not sys.platform.startswith('win'):
try:
os.chmod('/usr/local/bin/kindlegen', 0o755)
except Exception:
pass
kindleGenExitCode = Popen('kindlegen -locale en', stdout=PIPE, stderr=STDOUT, shell=True)
if kindleGenExitCode.wait() == 0:
self.KindleGen = True
versionCheck = Popen('kindlegen -locale en', stdout=PIPE, stderr=STDOUT, shell=True)
for line in versionCheck.stdout:
line = line.decode("utf-8")
if 'Amazon kindlegen' in line:
versionCheck = line.split('V')[1].split(' ')[0]
if tuple(map(int, (versionCheck.split(".")))) < tuple(map(int, ('2.9'.split(".")))):
self.addMessage('Your <a href="http://www.amazon.com/gp/feature.html?ie=UTF8&docId='
'1000765211">kindlegen</a> is outdated! Creating MOBI might fail.'
' Please update <a href="http://www.amazon.com/gp/feature.html?ie=UTF8&docId='
'1000765211">kindlegen</a> from Amazon\'s website.', 'warning')
break
else:
self.KindleGen = False
rarExitCode = Popen('unrar', stdout=PIPE, stderr=STDOUT, shell=True)
rarExitCode = rarExitCode.wait()
if rarExitCode == 0 or rarExitCode == 7:
@@ -1232,6 +1239,7 @@ class KCCGUI(KCC_ui.Ui_KCC):
self.sevenza = False
self.addMessage('Cannot find <a href="http://www.7-zip.org/download.html">7za</a>!'
' Processing of CB7/7Z files will be disabled.', 'warning')
self.detectKindleGen(True)
APP.messageFromOtherInstance.connect(self.handleMessage)
GUI.BasicModeButton.clicked.connect(self.modeBasic)
@@ -1239,6 +1247,7 @@ class KCCGUI(KCC_ui.Ui_KCC):
GUI.DirectoryButton.clicked.connect(self.selectDir)
GUI.ClearButton.clicked.connect(self.clearJobs)
GUI.FileButton.clicked.connect(self.selectFile)
GUI.EditorButton.clicked.connect(self.selectFileMetaEditor)
GUI.ConvertButton.clicked.connect(self.convertStart)
GUI.GammaSlider.valueChanged.connect(self.changeGamma)
GUI.NoRotateBox.stateChanged.connect(self.toggleNoSplitRotate)
@@ -1253,7 +1262,6 @@ class KCCGUI(KCC_ui.Ui_KCC):
MW.showDialog.connect(self.showDialog)
MW.hideProgressBar.connect(self.hideProgressBar)
MW.forceShutdown.connect(self.forceShutdown)
MW.dialogAnswer.connect(self.versionCheck.getNewVersion)
MW.closeEvent = self.saveSettings
MW.addTrayMessage.connect(self.tray.addTrayMessage)
@@ -1302,3 +1310,55 @@ class KCCGUI(KCC_ui.Ui_KCC):
MW.setWindowTitle("Kindle Comic Converter " + __version__)
MW.show()
MW.raise_()
class KCCGUI_MetaEditor(KCC_MetaEditor_ui.Ui_MetaEditorDialog):
def loadData(self, file):
self.parser = metadata.MetadataParser(file)
if self.parser.compressor == 'rar':
self.EditorFrame.setEnabled(False)
self.OKButton.setEnabled(False)
self.StatusLabel.setText('CBR metadata are read-only.')
else:
self.EditorFrame.setEnabled(True)
self.OKButton.setEnabled(True)
self.StatusLabel.setText('Separate authors with a comma.')
for field in (self.SeriesLine, self.VolumeLine, self.NumberLine, self.MUidLine):
field.setText(self.parser.data[field.objectName()[:-4]])
for field in (self.WriterLine, self.PencillerLine, self.InkerLine, self.ColoristLine):
field.setText(', '.join(self.parser.data[field.objectName()[:-4] + 's']))
if self.SeriesLine.text() == '':
self.SeriesLine.setText(file.split('\\')[-1].split('.')[0])
def saveData(self):
for field in (self.VolumeLine, self.NumberLine, self.MUidLine):
if field.text().isnumeric() or self.cleanData(field.text()) == '':
self.parser.data[field.objectName()[:-4]] = self.cleanData(field.text())
else:
self.StatusLabel.setText(field.objectName()[:-4] + ' field must be a number.')
break
else:
self.parser.data['Series'] = self.cleanData(self.SeriesLine.text())
for field in (self.WriterLine, self.PencillerLine, self.InkerLine, self.ColoristLine):
values = self.cleanData(field.text()).split(',')
tmpData = []
for value in values:
if self.cleanData(value) != '':
tmpData.append(self.cleanData(value))
self.parser.data[field.objectName()[:-4] + 's'] = tmpData
try:
self.parser.saveXML()
except:
GUI.showDialog('Failed to save metadata!', 'error')
self.ui.close()
def cleanData(self, s):
return escape(s.strip())
def __init__(self):
self.ui = QtWidgets.QDialog()
self.parser = None
self.setupUi(self.ui)
self.ui.setWindowFlags(self.ui.windowFlags() & ~QtCore.Qt.WindowContextHelpButtonHint)
self.OKButton.clicked.connect(self.saveData)
self.CancelButton.clicked.connect(self.ui.close)

File diff suppressed because it is too large Load Diff

View File

@@ -2,8 +2,8 @@
# Form implementation generated from reading ui file 'KCC.ui'
#
# Created: Sun May 18 09:08:27 2014
# by: PyQt5 UI code generator 5.2.1
# Created: Sun Feb 8 09:50:43 2015
# by: PyQt5 UI code generator 5.4
#
# WARNING! All changes made in this file will be lost!
@@ -141,18 +141,16 @@ class Ui_KCC(object):
self.JobList.setStyleSheet("QListWidget#JobList {background:#ffffff;background-image:url(:/Other/icons/list_background.png);background-position:center center;background-repeat:no-repeat;}QScrollBar:vertical{border:1px solid #999;background:#FFF;width:5px;margin:0}QScrollBar::handle:vertical{background:DarkGray;min-height:0}QScrollBar::add-line:vertical{height:0;background:DarkGray;subcontrol-position:bottom;subcontrol-origin:margin}QScrollBar::sub-line:vertical{height:0;background:DarkGray;subcontrol-position:top;subcontrol-origin:margin}QScrollBar:horizontal{border:1px solid #999;background:#FFF;height:5px;margin:0}QScrollBar::handle:horizontal{background:DarkGray;min-width:0}QScrollBar::add-line:horizontal{width:0;background:DarkGray;subcontrol-position:bottom;subcontrol-origin:margin}QScrollBar::sub-line:horizontal{width:0;background:DarkGray;subcontrol-position:top;subcontrol-origin:margin}")
self.JobList.setProperty("showDropIndicator", False)
self.JobList.setSelectionMode(QtWidgets.QAbstractItemView.NoSelection)
self.JobList.setVerticalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel)
self.JobList.setHorizontalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel)
self.JobList.setObjectName("JobList")
self.BasicModeButton = QtWidgets.QPushButton(self.Form)
self.BasicModeButton.setGeometry(QtCore.QRect(10, 10, 195, 32))
self.BasicModeButton.setGeometry(QtCore.QRect(10, 10, 141, 32))
font = QtGui.QFont()
font.setPointSize(9)
self.BasicModeButton.setFont(font)
self.BasicModeButton.setFocusPolicy(QtCore.Qt.NoFocus)
self.BasicModeButton.setObjectName("BasicModeButton")
self.AdvModeButton = QtWidgets.QPushButton(self.Form)
self.AdvModeButton.setGeometry(QtCore.QRect(217, 10, 195, 32))
self.AdvModeButton.setGeometry(QtCore.QRect(261, 10, 151, 32))
font = QtGui.QFont()
font.setPointSize(9)
self.AdvModeButton.setFont(font)
@@ -231,6 +229,16 @@ class Ui_KCC(object):
self.customHeight.setMaxLength(4)
self.customHeight.setObjectName("customHeight")
self.gridLayout_2.addWidget(self.customHeight, 0, 3, 1, 1)
self.EditorButton = QtWidgets.QPushButton(self.Form)
self.EditorButton.setGeometry(QtCore.QRect(160, 10, 91, 32))
font = QtGui.QFont()
font.setPointSize(9)
self.EditorButton.setFont(font)
self.EditorButton.setFocusPolicy(QtCore.Qt.NoFocus)
icon5 = QtGui.QIcon()
icon5.addPixmap(QtGui.QPixmap(":/Other/icons/editor.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.EditorButton.setIcon(icon5)
self.EditorButton.setObjectName("EditorButton")
KCC.setCentralWidget(self.Form)
self.statusBar = QtWidgets.QStatusBar(KCC)
font = QtGui.QFont()
@@ -260,28 +268,30 @@ class Ui_KCC(object):
def retranslateUi(self, KCC):
_translate = QtCore.QCoreApplication.translate
KCC.setWindowTitle(_translate("KCC", "Kindle Comic Converter"))
self.ProcessingBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Disable image optimizations.<br/>Input images must be already resized.</p></body></html>"))
self.ProcessingBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Disable image optimizations.<br/><span style=\" font-weight:600;\">Input images must be already resized.</span></p></body></html>"))
self.ProcessingBox.setText(_translate("KCC", "No optimisation"))
self.UpscaleBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Nothing<br/></span>Images smaller than device resolution will not be resized.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - Stretching<br/></span>Images smaller than device resolution will be resized. Aspect ratio will be not preserved.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Upscaling<br/></span>Images smaller than device resolution will be resized. Aspect ratio will be preserved.</p></body></html>"))
self.UpscaleBox.setText(_translate("KCC", "Stretch/Upscale"))
self.WebtoonBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\"white-space:pre\">Enable auto-splitting of webtoons like <span style=\" font-style:italic;\">Tower of God</span> or <span style=\" font-style:italic;\">Noblesse</span>.<br/>This mode is created for pages with a low width, high height and vertical panel flow.</p></body></html>"))
self.WebtoonBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Enable special parsing mode for WebToons.</p></body></html>"))
self.WebtoonBox.setText(_translate("KCC", "Webtoon mode"))
self.NoDitheringBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Create PNG files instead JPEG.<br/>Quality increase is not noticeable on most of devices.<br/>Output files <span style=\" font-weight:600;\">might</span> be smaller.<br/><span style=\" font-weight:600;\">MOBI conversion will be much slower.</span></p></body></html>"))
self.NoDitheringBox.setText(_translate("KCC", "PNG output"))
self.BorderBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Autodetection<br/></span>Color of margins fill will be detected automatically.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - White<br/></span>Margins will be filled with white color.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Black<br/></span>Margins will be filled with black color.</p></body></html>"))
self.BorderBox.setText(_translate("KCC", "W/B margins"))
self.NoRotateBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Disable splitting and rotation.</p></body></html>"))
self.NoRotateBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Disable page splitting and rotation.</p></body></html>"))
self.NoRotateBox.setText(_translate("KCC", "No split/rotate"))
self.DeviceBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Target device.</p></body></html>"))
self.FormatBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Output format.</p></body></html>"))
self.ConvertButton.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Shift+Click to select the output directory.</p></body></html>"))
self.ConvertButton.setText(_translate("KCC", "Convert"))
self.DirectoryButton.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Add directory containing JPG, PNG or GIF files to queue.<br/><span style=\" font-weight:600;\">CBR, CBZ and CB7 files inside will not be processed!</span></p></body></html>"))
self.DirectoryButton.setText(_translate("KCC", "Add directory"))
self.FileButton.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Add CBR, CBZ, CB7 or PDF file to queue.</p></body></html>"))
self.FileButton.setText(_translate("KCC", "Add file"))
self.ClearButton.setText(_translate("KCC", "Clear list"))
self.MangaBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Enable right-to-left reading.</p></body></html>"))
self.MangaBox.setText(_translate("KCC", "Manga mode"))
self.QualityBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\"white-space:pre\"><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Normal quality mode<br/></span>Maximal quality of images but very poor magnification quality.<br/>Use it only when zoom is not needed or output files needs to be small.</p><p style=\"white-space:pre\"><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - High quality mode<br/></span>In most cases high quality of images and magnification.<br/>Overall quality highly depends on the resolution of source files.<br/>On Kindle models older than Paperwhite non-zoomed images might be a little blurred.</p><p style=\"white-space:pre\"><span style=\" font-weight:600; text-decoration: underline;\">Checked - Ultra quality mode<br/></span>Highest possible quality. Output files will be big.</p></body></html>"))
self.QualityBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Quality of Panel View/zoom. Highly impact size of output file.<br/><span style=\" font-weight:600;\">This option control only quality of magnification!</span></p></body></html>"))
self.QualityBox.setText(_translate("KCC", "High/Ultra quality"))
self.RotateBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Disable splitting of two-page spreads.<br/>They will be rotated instead.</p></body></html>"))
self.RotateBox.setText(_translate("KCC", "Horizontal mode"))
@@ -298,6 +308,7 @@ class Ui_KCC(object):
self.hLabel.setText(_translate("KCC", "Custom height: "))
self.customHeight.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Resolution of target device.</p></body></html>"))
self.customHeight.setInputMask(_translate("KCC", "0000"))
self.EditorButton.setText(_translate("KCC", "Editor"))
self.ActionBasic.setText(_translate("KCC", "Basic"))
self.ActionAdvanced.setText(_translate("KCC", "Advanced"))

View File

@@ -1,8 +1,8 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'KCC-Linux.ui'
# Form implementation generated from reading ui file 'gui/KCC-Linux.ui'
#
# Created: Sun May 18 09:08:37 2014
# Created: Sun Feb 8 03:10:09 2015
# by: PyQt5 UI code generator 5.2.1
#
# WARNING! All changes made in this file will be lost!
@@ -182,11 +182,9 @@ class Ui_KCC(object):
self.JobList.setProperty("showDropIndicator", False)
self.JobList.setSelectionMode(QtWidgets.QAbstractItemView.NoSelection)
self.JobList.setIconSize(QtCore.QSize(18, 18))
self.JobList.setVerticalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel)
self.JobList.setHorizontalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel)
self.JobList.setObjectName("JobList")
self.BasicModeButton = QtWidgets.QPushButton(self.Form)
self.BasicModeButton.setGeometry(QtCore.QRect(10, 10, 195, 32))
self.BasicModeButton.setGeometry(QtCore.QRect(10, 10, 141, 32))
font = QtGui.QFont()
font.setFamily("DejaVu Sans")
font.setPointSize(9)
@@ -194,7 +192,7 @@ class Ui_KCC(object):
self.BasicModeButton.setFocusPolicy(QtCore.Qt.NoFocus)
self.BasicModeButton.setObjectName("BasicModeButton")
self.AdvModeButton = QtWidgets.QPushButton(self.Form)
self.AdvModeButton.setGeometry(QtCore.QRect(217, 10, 195, 32))
self.AdvModeButton.setGeometry(QtCore.QRect(260, 10, 151, 32))
font = QtGui.QFont()
font.setFamily("DejaVu Sans")
font.setPointSize(9)
@@ -301,6 +299,17 @@ class Ui_KCC(object):
self.customHeight.setMaxLength(4)
self.customHeight.setObjectName("customHeight")
self.gridLayout_2.addWidget(self.customHeight, 0, 3, 1, 1)
self.EditorButton = QtWidgets.QPushButton(self.Form)
self.EditorButton.setGeometry(QtCore.QRect(160, 10, 91, 32))
font = QtGui.QFont()
font.setFamily("DejaVu Sans")
font.setPointSize(9)
self.EditorButton.setFont(font)
self.EditorButton.setFocusPolicy(QtCore.Qt.NoFocus)
icon5 = QtGui.QIcon()
icon5.addPixmap(QtGui.QPixmap(":/Other/icons/editor.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.EditorButton.setIcon(icon5)
self.EditorButton.setObjectName("EditorButton")
KCC.setCentralWidget(self.Form)
self.statusBar = QtWidgets.QStatusBar(KCC)
font = QtGui.QFont()
@@ -329,28 +338,30 @@ class Ui_KCC(object):
def retranslateUi(self, KCC):
_translate = QtCore.QCoreApplication.translate
KCC.setWindowTitle(_translate("KCC", "Kindle Comic Converter"))
self.ProcessingBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Disable image optimizations.<br/>Input images must be already resized.</p></body></html>"))
self.ProcessingBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Disable image optimizations.<br/><span style=\" font-weight:600;\">Input images must be already resized.</span></p></body></html>"))
self.ProcessingBox.setText(_translate("KCC", "No optimisation"))
self.UpscaleBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Nothing<br/></span>Images smaller than device resolution will not be resized.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - Stretching<br/></span>Images smaller than device resolution will be resized. Aspect ratio will be not preserved.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Upscaling<br/></span>Images smaller than device resolution will be resized. Aspect ratio will be preserved.</p></body></html>"))
self.UpscaleBox.setText(_translate("KCC", "Stretch/Upscale"))
self.WebtoonBox.setToolTip(_translate("KCC", "<html><head/><body><p>Enable auto-splitting of webtoons like <span style=\" font-style:italic;\">Tower of God</span> or <span style=\" font-style:italic;\">Noblesse</span>.<br/>This mode was created for pages with a low width, high height and vertical panel flow.</p></body></html>"))
self.WebtoonBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Enable special parsing mode for WebToons.</p></body></html>"))
self.WebtoonBox.setText(_translate("KCC", "Webtoon mode"))
self.NoDitheringBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Create PNG files instead JPEG.<br/>Quality increase is not noticeable on most of devices.<br/>Output files <span style=\" font-weight:600;\">might</span> be smaller.<br/><span style=\" font-weight:600;\">MOBI conversion will be much slower.</span></p></body></html>"))
self.NoDitheringBox.setText(_translate("KCC", "PNG output"))
self.BorderBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Autodetection<br/></span>Color of margins fill will be detected automatically.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - White<br/></span>Margins will be filled with white color.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Black<br/></span>Margins will be filled with black color.</p></body></html>"))
self.BorderBox.setText(_translate("KCC", "W/B margins"))
self.NoRotateBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Disable splitting and rotation.</p></body></html>"))
self.NoRotateBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Disable page splitting and rotation.</p></body></html>"))
self.NoRotateBox.setText(_translate("KCC", "No split/rotate"))
self.DeviceBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Target device.</p></body></html>"))
self.FormatBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Output format.</p></body></html>"))
self.ConvertButton.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Shift+Click to select the output directory.</p></body></html>"))
self.ConvertButton.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Shift+Click to select the output directory.</p></body></html>"))
self.ConvertButton.setText(_translate("KCC", "Convert"))
self.DirectoryButton.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Add directory containing JPG, PNG or GIF files to queue.<br/><span style=\" font-weight:600;\">CBR, CBZ and CB7 files inside will not be processed!</span></p></body></html>"))
self.DirectoryButton.setText(_translate("KCC", "Add directory"))
self.FileButton.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Add CBR, CBZ, CB7 or PDF file to queue.</p></body></html>"))
self.FileButton.setText(_translate("KCC", "Add file"))
self.ClearButton.setText(_translate("KCC", "Clear list"))
self.MangaBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Enable right-to-left reading.</p></body></html>"))
self.MangaBox.setText(_translate("KCC", "Manga mode"))
self.QualityBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Normal quality mode</span><br/>Maximal quality of images but very poor magnification quality.<br/>Use it only when zoom is not needed or output files needs to be small.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - High quality mode</span><br/>In most cases high quality of images and magnification.<br/>Overall quality highly depends on the resolution of source files.<br/>On Kindle models older than Paperwhite non-zoomed images might be a little blurred.<br/><br/><span style=\" font-weight:600; text-decoration: underline;\">Checked - Ultra quality mode</span><br/>Highest possible quality. Output files will be big.</p></body></html>"))
self.QualityBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Quality of Panel View/zoom. Highly impact size of output file.<br/><span style=\" font-weight:600;\">This option control only quality of magnification!</span></p></body></html>"))
self.QualityBox.setText(_translate("KCC", "High/Ultra quality"))
self.RotateBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Disable splitting of two-page spreads.<br/>They will be rotated instead.</p></body></html>"))
self.RotateBox.setText(_translate("KCC", "Horizontal mode"))
@@ -359,14 +370,15 @@ class Ui_KCC(object):
self.GammaLabel.setText(_translate("KCC", "Gamma: Auto"))
self.ColorBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Don\'t convert images to grayscale.</p></body></html>"))
self.ColorBox.setText(_translate("KCC", "Color mode"))
self.wLabel.setToolTip(_translate("KCC", "<html><head/><body><p>Resolution of target device.</p></body></html>"))
self.wLabel.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Resolution of target device.</p></body></html>"))
self.wLabel.setText(_translate("KCC", "Custom width: "))
self.customWidth.setToolTip(_translate("KCC", "<html><head/><body><p>Resolution of target device.</p></body></html>"))
self.customWidth.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Resolution of target device.</p></body></html>"))
self.customWidth.setInputMask(_translate("KCC", "0000"))
self.hLabel.setToolTip(_translate("KCC", "<html><head/><body><p>Resolution of target device.</p></body></html>"))
self.hLabel.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Resolution of target device.</p></body></html>"))
self.hLabel.setText(_translate("KCC", "Custom height: "))
self.customHeight.setToolTip(_translate("KCC", "<html><head/><body><p>Resolution of target device.</p></body></html>"))
self.customHeight.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Resolution of target device.</p></body></html>"))
self.customHeight.setInputMask(_translate("KCC", "0000"))
self.EditorButton.setText(_translate("KCC", "Editor"))
self.ActionBasic.setText(_translate("KCC", "Basic"))
self.ActionAdvanced.setText(_translate("KCC", "Advanced"))

View File

@@ -1,9 +1,9 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'KCC-OSX.ui'
# Form implementation generated from reading ui file '/Users/pawelj/Documents/KCC/gui/KCC-OSX.ui'
#
# Created: Sun May 18 09:08:44 2014
# by: PyQt5 UI code generator 5.2.1
# Created: Sun Feb 8 12:37:33 2015
# by: PyQt5 UI code generator 5.4
#
# WARNING! All changes made in this file will be lost!
@@ -188,11 +188,9 @@ class Ui_KCC(object):
self.JobList.setStyleSheet("QListWidget#JobList {background:#ffffff;background-image:url(:/Other/icons/list_background.png);background-position:center center;background-repeat:no-repeat;}QScrollBar:vertical{border:1px solid #999;background:#FFF;width:5px;margin:0}QScrollBar::handle:vertical{background:DarkGray;min-height:0}QScrollBar::add-line:vertical{height:0;background:DarkGray;subcontrol-position:bottom;subcontrol-origin:margin}QScrollBar::sub-line:vertical{height:0;background:DarkGray;subcontrol-position:top;subcontrol-origin:margin}QScrollBar:horizontal{border:1px solid #999;background:#FFF;height:5px;margin:0}QScrollBar::handle:horizontal{background:DarkGray;min-width:0}QScrollBar::add-line:horizontal{width:0;background:DarkGray;subcontrol-position:bottom;subcontrol-origin:margin}QScrollBar::sub-line:horizontal{width:0;background:DarkGray;subcontrol-position:top;subcontrol-origin:margin}")
self.JobList.setProperty("showDropIndicator", False)
self.JobList.setSelectionMode(QtWidgets.QAbstractItemView.NoSelection)
self.JobList.setVerticalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel)
self.JobList.setHorizontalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel)
self.JobList.setObjectName("JobList")
self.BasicModeButton = QtWidgets.QPushButton(self.Form)
self.BasicModeButton.setGeometry(QtCore.QRect(5, 10, 210, 41))
self.BasicModeButton.setGeometry(QtCore.QRect(5, 10, 156, 41))
font = QtGui.QFont()
font.setFamily("Lucida Grande")
font.setPointSize(12)
@@ -202,7 +200,7 @@ class Ui_KCC(object):
self.BasicModeButton.setFocusPolicy(QtCore.Qt.NoFocus)
self.BasicModeButton.setObjectName("BasicModeButton")
self.AdvModeButton = QtWidgets.QPushButton(self.Form)
self.AdvModeButton.setGeometry(QtCore.QRect(207, 10, 210, 41))
self.AdvModeButton.setGeometry(QtCore.QRect(260, 10, 156, 41))
font = QtGui.QFont()
font.setFamily("Lucida Grande")
font.setPointSize(12)
@@ -323,6 +321,17 @@ class Ui_KCC(object):
self.customHeight.setMaxLength(4)
self.customHeight.setObjectName("customHeight")
self.gridLayout_2.addWidget(self.customHeight, 0, 3, 1, 1)
self.EditorButton = QtWidgets.QPushButton(self.Form)
self.EditorButton.setGeometry(QtCore.QRect(160, 10, 101, 41))
font = QtGui.QFont()
font.setFamily("Lucida Grande")
font.setPointSize(12)
self.EditorButton.setFont(font)
self.EditorButton.setFocusPolicy(QtCore.Qt.NoFocus)
icon5 = QtGui.QIcon()
icon5.addPixmap(QtGui.QPixmap(":/Other/icons/editor.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.EditorButton.setIcon(icon5)
self.EditorButton.setObjectName("EditorButton")
KCC.setCentralWidget(self.Form)
self.statusBar = QtWidgets.QStatusBar(KCC)
font = QtGui.QFont()
@@ -352,28 +361,30 @@ class Ui_KCC(object):
def retranslateUi(self, KCC):
_translate = QtCore.QCoreApplication.translate
KCC.setWindowTitle(_translate("KCC", "Kindle Comic Converter"))
self.ProcessingBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Disable image optimizations.<br/>Input images must be already resized.</p></body></html>"))
self.ProcessingBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Disable image optimizations.<br/><span style=\" font-weight:600;\">Input images must be already resized.</span></p></body></html>"))
self.ProcessingBox.setText(_translate("KCC", "No optimisation"))
self.UpscaleBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Nothing<br/></span>Images smaller than device resolution will not be resized.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - Stretching<br/></span>Images smaller than device resolution will be resized. Aspect ratio will be not preserved.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Upscaling<br/></span>Images smaller than device resolution will be resized. Aspect ratio will be preserved.</p></body></html>"))
self.UpscaleBox.setText(_translate("KCC", "Stretch/Upscale"))
self.WebtoonBox.setToolTip(_translate("KCC", "<html><head/><body><p>Enable auto-splitting of webtoons like <span style=\" font-style:italic;\">Tower of God </span>or <span style=\" font-style:italic;\">Noblesse</span>.<br/>This mode was created for pages with a low width, high height and vertical panel flow.</p><p><br/></p></body></html>"))
self.WebtoonBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Enable special parsing mode for WebToons.</p></body></html>"))
self.WebtoonBox.setText(_translate("KCC", "Webtoon mode"))
self.NoDitheringBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Create PNG files instead JPEG.<br/>Quality increase is not noticeable on most of devices.<br/>Output files <span style=\" font-weight:600;\">might</span> be smaller.<br/><span style=\" font-weight:600;\">MOBI conversion will be much slower.</span></p></body></html>"))
self.NoDitheringBox.setText(_translate("KCC", "PNG output"))
self.BorderBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Autodetection<br/></span>Color of margins fill will be detected automatically.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - White<br/></span>Margins will be filled with white color.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Black<br/></span>Margins will be filled with black color.</p></body></html>"))
self.BorderBox.setText(_translate("KCC", "W/B margins"))
self.NoRotateBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Disable splitting and rotation.</p></body></html>"))
self.NoRotateBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Disable page splitting and rotation.</p></body></html>"))
self.NoRotateBox.setText(_translate("KCC", "No split/rotate"))
self.DeviceBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Target device.</p></body></html>"))
self.FormatBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Output format.</p></body></html>"))
self.ConvertButton.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Shift+Click to select the output directory.</p></body></html>"))
self.FormatBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Output format.</p></body></html>"))
self.ConvertButton.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Shift+Click to select the output directory.</p></body></html>"))
self.ConvertButton.setText(_translate("KCC", "Convert"))
self.DirectoryButton.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Add directory containing JPG, PNG or GIF files to queue.<br/><span style=\" font-weight:600;\">CBR, CBZ and CB7 files inside will not be processed!</span></p></body></html>"))
self.DirectoryButton.setText(_translate("KCC", "Add directory"))
self.FileButton.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Add CBR, CBZ, CB7 or PDF file to queue.</p></body></html>"))
self.FileButton.setText(_translate("KCC", "Add file"))
self.ClearButton.setText(_translate("KCC", "Clear list"))
self.MangaBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Enable right-to-left reading.</p></body></html>"))
self.MangaBox.setText(_translate("KCC", "Manga mode"))
self.QualityBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Normal quality mode</span><br/>Maximal quality of images but very poor magnification quality.<br/>Use it only when zoom is not needed or output files needs to be small.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - High quality mode</span><br/>In most cases high quality of images and magnification.<br/>Overall quality highly depends on the resolution of source files.<br/>On Kindle models older than Paperwhite non-zoomed images might be a little blurred.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Ultra quality mode</span><br/>Highest possible quality. Output files will be big.</p></body></html>"))
self.QualityBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Quality of Panel View/zoom. Highly impact size of output file.<br/><span style=\" font-weight:600;\">This option control only quality of magnification!</span></p></body></html>"))
self.QualityBox.setText(_translate("KCC", "High/Ultra quality"))
self.RotateBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Disable splitting of two-page spreads.<br/>They will be rotated instead.</p></body></html>"))
self.RotateBox.setText(_translate("KCC", "Horizontal mode"))
@@ -390,6 +401,7 @@ class Ui_KCC(object):
self.hLabel.setText(_translate("KCC", "Custom height: "))
self.customHeight.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Resolution of target device.</p></body></html>"))
self.customHeight.setInputMask(_translate("KCC", "0000"))
self.EditorButton.setText(_translate("KCC", "Editor"))
self.ActionBasic.setText(_translate("KCC", "Basic"))
self.ActionAdvanced.setText(_translate("KCC", "Advanced"))

View File

@@ -1,4 +1,4 @@
__version__ = '4.2.1'
__version__ = '4.6.2'
__license__ = 'ISC'
__copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>'
__docformat__ = 'restructuredtext en'
__copyright__ = '2012-2015, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>'
__docformat__ = 'restructuredtext en'

View File

@@ -1,5 +1,5 @@
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
# Copyright (c) 2013-2014 Pawel Jastrzebski <pawelj@iosphe.re>
# Copyright (c) 2013-2015 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
@@ -16,17 +16,15 @@
# PERFORMANCE OF THIS SOFTWARE.
#
__license__ = 'ISC'
__copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>'
__docformat__ = 'restructuredtext en'
import sys
import os
from zipfile import is_zipfile, ZipFile
from subprocess import STDOUT, PIPE
from psutil import Popen
from shutil import move, copy
from scandir import walk
from . import rarfile
from .shared import check7ZFile as is_7zfile, saferReplace
class CBxArchive:
@@ -36,7 +34,7 @@ class CBxArchive:
self.compressor = 'zip'
elif rarfile.is_rarfile(origFileName):
self.compressor = 'rar'
elif origFileName.endswith('.7z') or origFileName.endswith('.cb7'):
elif is_7zfile(origFileName):
self.compressor = '7z'
else:
self.compressor = None
@@ -48,7 +46,7 @@ class CBxArchive:
cbzFile = ZipFile(self.origFileName)
filelist = []
for f in cbzFile.namelist():
if f.startswith('__MACOSX') or f.endswith('.DS_Store') or f.endswith('thumbs.db'):
if f.startswith('__MACOSX') or f.endswith('.DS_Store') or f.endswith('humbs.db'):
pass # skip MacOS special files
elif f.endswith('/'):
try:
@@ -61,25 +59,18 @@ class CBxArchive:
def extractCBR(self, targetdir):
cbrFile = rarfile.RarFile(self.origFileName)
filelist = []
for f in cbrFile.namelist():
if f.startswith('__MACOSX') or f.endswith('.DS_Store') or f.endswith('thumbs.db'):
pass # skip MacOS special files
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.
else:
filelist.append(f)
cbrFile.extractall(targetdir, filelist)
cbrFile.extractall(targetdir)
for root, dirnames, filenames in walk(targetdir):
for filename in filenames:
if filename.startswith('__MACOSX') or filename.endswith('.DS_Store') or filename.endswith('humbs.db'):
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 -o"'
output = Popen('7za x "' + self.origFileName + '" -xr!__MACOSX -xr!.DS_Store -xr!thumbs.db -xr!Thumbs.db -o"'
+ targetdir + '"', stdout=PIPE, stderr=STDOUT, shell=True)
extracted = False
for line in output.stdout:
@@ -104,7 +95,7 @@ class CBxArchive:
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)):
os.replace(os.path.join(targetdir, adir[0], f), os.path.join(targetdir, adir[0], f + '-A'))
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]))

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
# Copyright (c) 2013-2014 Pawel Jastrzebski <pawelj@iosphe.re>
# Copyright (c) 2013-2015 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
@@ -18,18 +18,14 @@
# PERFORMANCE OF THIS SOFTWARE.
#
__version__ = '4.2.1'
__license__ = 'ISC'
__copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>'
__docformat__ = 'restructuredtext en'
import os
import sys
from shutil import rmtree, copytree, move
from optparse import OptionParser, OptionGroup
from multiprocessing import Pool
from PIL import Image, ImageStat
from .shared import getImageFileName, walkLevel
from PIL import Image, ImageStat, ImageOps
from scandir import walk
from .shared import getImageFileName, walkLevel, walkSort
try:
from PyQt5 import QtCore
except ImportError:
@@ -50,9 +46,9 @@ def mergeDirectory(work):
try:
directory = work[0]
images = []
imagesClear = []
imagesValid = []
sizes = []
h = 0
targetHeight = 0
for root, dirs, files in walkLevel(directory, 0):
for name in files:
if getImageFileName(name) is not None:
@@ -60,23 +56,26 @@ def mergeDirectory(work):
images.append([os.path.join(root, name), i.size[0], i.size[1]])
sizes.append(i.size[0])
if len(images) > 0:
mw = max(set(sizes), key=sizes.count)
targetWidth = max(set(sizes), key=sizes.count)
for i in images:
if i[1] == mw:
h += i[2]
imagesClear.append(i[0])
if i[1] <= targetWidth:
targetHeight += i[2]
imagesValid.append(i[0])
# Silently drop directories that contain too many images
if h > 262144:
# 131072 = GIMP_MAX_IMAGE_SIZE / 4
if targetHeight > 131072:
return None
result = Image.new('RGB', (mw, h))
result = Image.new('RGB', (targetWidth, targetHeight))
y = 0
for i in imagesClear:
for i in imagesValid:
img = Image.open(i)
img = img.convert('RGB')
if img.size[0] < targetWidth:
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]
os.remove(i)
savePath = os.path.split(imagesClear[0])
savePath = os.path.split(imagesValid[0])
result.save(os.path.join(savePath[0], os.path.splitext(savePath[1])[0] + '.png'), 'PNG')
except Exception:
return str(sys.exc_info()[1])
@@ -84,7 +83,7 @@ def mergeDirectory(work):
def sanitizePanelSize(panel, opt):
newPanels = []
if panel[2] > 8 * opt.height:
if panel[2] > 6 * opt.height:
diff = int(panel[2] / 8)
newPanels.append([panel[0], panel[1] - diff*7, diff])
newPanels.append([panel[1] - diff*7, panel[1] - diff*6, diff])
@@ -94,13 +93,13 @@ def sanitizePanelSize(panel, opt):
newPanels.append([panel[1] - diff*3, panel[1] - diff*2, diff])
newPanels.append([panel[1] - diff*2, panel[1] - diff, diff])
newPanels.append([panel[1] - diff, panel[1], diff])
elif panel[2] > 4 * opt.height:
elif panel[2] > 3 * opt.height:
diff = int(panel[2] / 4)
newPanels.append([panel[0], panel[1] - diff*3, diff])
newPanels.append([panel[1] - diff*3, panel[1] - diff*2, diff])
newPanels.append([panel[1] - diff*2, panel[1] - diff, diff])
newPanels.append([panel[1] - diff, panel[1], diff])
elif panel[2] > 2 * opt.height:
elif panel[2] > 1.5 * opt.height:
newPanels.append([panel[0], panel[1] - int(panel[2] / 2), int(panel[2] / 2)])
newPanels.append([panel[1] - int(panel[2] / 2), panel[1], int(panel[2] / 2)])
else:
@@ -118,7 +117,6 @@ def splitImageTick(output):
splitWorkerPool.terminate()
#noinspection PyUnboundLocalVariable
def splitImage(work):
try:
path = work[0]
@@ -165,6 +163,7 @@ def splitImage(work):
for panel in panelsCleaned:
panels.append(panel)
if opt.debug:
# noinspection PyUnboundLocalVariable
debugImage.save(os.path.join(path, fileExpanded[0] + '-debug.png'), 'PNG')
# Create virtual pages
@@ -199,8 +198,7 @@ def splitImage(work):
panelImg = image.crop([0, panels[panel][0], widthImg, panels[panel][1]])
newPage.paste(panelImg, (0, targetHeight))
targetHeight += panels[panel][2]
newPage.save(os.path.join(path, fileExpanded[0] + '-' +
str(pageNumber) + '.png'), 'PNG')
newPage.save(os.path.join(path, fileExpanded[0] + '-' + str(pageNumber) + '.png'), 'PNG')
pageNumber += 1
os.remove(filePath)
except Exception:
@@ -249,7 +247,8 @@ def main(argv=None, qtGUI=None):
mergeWorkerOutput = []
mergeWorkerPool = Pool()
mergeWork.append([options.targetDir])
for root, dirs, files in os.walk(options.targetDir, False):
for root, dirs, files in walk(options.targetDir, False):
dirs, files = walkSort(dirs, files)
for directory in dirs:
directoryNumer += 1
mergeWork.append([os.path.join(root, directory)])
@@ -267,7 +266,7 @@ def main(argv=None, qtGUI=None):
rmtree(options.targetDir, True)
raise RuntimeError("One of workers crashed. Cause: " + mergeWorkerOutput[0])
print("\nSplitting images...")
for root, dirs, files in os.walk(options.targetDir, False):
for root, dirs, files in walk(options.targetDir, False):
for name in files:
if getImageFileName(name) is not None:
pagenumber += 1
@@ -298,4 +297,4 @@ def main(argv=None, qtGUI=None):
else:
raise UserWarning("Provided path is not a directory.")
else:
raise UserWarning("Target height is not set.")
raise UserWarning("Target height is not set.")

View File

@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
#
# Based on initial version of DualMetaFix. Copyright (C) 2013 Kevin Hendricks
# Changes for KCC Copyright (C) 2014 Pawel Jastrzebski <pawelj@iosphe.re>
# Changes for KCC Copyright (C) 2014-2015 Pawel Jastrzebski <pawelj@iosphe.re>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -181,4 +181,4 @@ class DualMobiMetaFix:
replacesection(self.datain, datain_kf8, rec0)
self.datain.flush()
self.datain.close()
self.datain.close()

View File

@@ -1,7 +1,7 @@
# Copyright (C) 2010 Alex Yatskov
# Copyright (C) 2011 Stanislav (proDOOMman) Kosolapov <prodoomman@gmail.com>
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
# Copyright (c) 2013-2014 Pawel Jastrzebski <pawelj@iosphe.re>
# Copyright (c) 2013-2015 Pawel Jastrzebski <pawelj@iosphe.re>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -16,11 +16,6 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
__version__ = '4.2.1'
__license__ = 'ISC'
__copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>'
__docformat__ = 'restructuredtext en'
import os
from io import BytesIO
from urllib.request import Request, urlopen
@@ -28,6 +23,7 @@ from urllib.parse import quote
from functools import reduce
from PIL import Image, ImageOps, ImageStat, ImageChops
from .shared import md5Checksum
from . import __version__
class ProfileData:
@@ -85,80 +81,91 @@ class ProfileData:
'K1': ("Kindle 1", (600, 670), Palette4, 1.8, (900, 1005)),
'K2': ("Kindle 2", (600, 670), Palette15, 1.8, (900, 1005)),
'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)),
'KF': ("Kindle Fire", (600, 1024), PalleteNull, 1.0, (900, 1536)),
'KFHD': ("K. Fire HD 7\"", (800, 1280), PalleteNull, 1.0, (1200, 1920)),
'KFHD8': ("K. Fire HD 8.9\"", (1200, 1920), PalleteNull, 1.0, (1800, 2880)),
'KFHDX': ("K. Fire HDX 7\"", (1200, 1920), PalleteNull, 1.0, (1800, 2880)),
'KFHDX8': ("K. Fire HDX 8.9\"", (1600, 2560), PalleteNull, 1.0, (2400, 3840)),
'KPW': ("Kindle Paperwhite 1/2", (758, 1024), Palette16, 1.8, (1137, 1536)),
'KV': ("Kindle Paperwhite 3/Voyage", (1072, 1448), Palette16, 1.8, (1608, 2172)),
'KoMT': ("Kobo Mini/Touch", (600, 800), Palette16, 1.8, (900, 1200)),
'KoG': ("Kobo Glow", (768, 1024), Palette16, 1.8, (1152, 1536)),
'KoG': ("Kobo Glo", (768, 1024), Palette16, 1.8, (1152, 1536)),
'KoGHD': ("Kobo Glo HD", (1072, 1448), Palette16, 1.8, (1608, 2172)),
'KoA': ("Kobo Aura", (758, 1024), Palette16, 1.8, (1137, 1536)),
'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)),
}
class ComicPage:
def __init__(self, source, device, fill=None):
def __init__(self, source, options, original=None):
try:
self.profile_label, self.size, self.palette, self.gamma, self.panelviewsize = device
self.profile_label, self.size, self.palette, self.gamma, self.panelviewsize = options.profileData
except KeyError:
raise RuntimeError('Unexpected output device %s' % device)
raise RuntimeError('Unexpected output device %s' % options.profileData)
self.origFileName = source
self.filename = os.path.basename(self.origFileName)
self.image = Image.open(source)
self.image = self.image.convert('RGB')
self.color = self.isImageColor()
self.rotated = None
self.border = None
self.noHPV = None
self.noVPV = None
self.noPV = None
self.purge = False
self.hq = False
if fill:
self.fill = fill
self.opt = options
if original:
self.second = True
self.rotated = original.rotated
self.border = original.border
self.noHPV = original.noHPV
self.noVPV = original.noVPV
self.noPV = original.noPV
self.noHQ = original.noHQ
self.fill = original.fill
self.color = original.color
if self.rotated:
self.image = self.image.rotate(90, Image.BICUBIC, True)
self.opt.quality = 0
else:
self.second = False
self.rotated = None
self.border = None
self.noHPV = None
self.noVPV = None
self.noPV = None
self.fill = None
def saveToDir(self, targetdir, forcepng, color):
try:
if not self.purge:
flags = []
filename = os.path.join(targetdir, os.path.splitext(self.filename)[0]) + '-KCC'
if not color and not forcepng:
self.image = self.image.convert('L')
if self.rotated:
flags.append('Rotated')
if self.hq:
flags.append('HighQuality')
filename += '-HQ'
if self.noPV:
flags.append('NoPanelView')
else:
if self.noHPV:
flags.append('NoHorizontalPanelView')
if self.noVPV:
flags.append('NoVerticalPanelView')
if self.border:
flags.append("Margins-" + str(self.border[0]) + "-" + str(self.border[1]) + "-"
+ str(self.border[2]) + "-" + str(self.border[3]))
if forcepng:
filename += ".png"
self.image.save(filename, "PNG", optimize=1)
else:
filename += ".jpg"
self.image.save(filename, "JPEG", optimize=1)
return [md5Checksum(filename), flags]
self.noHQ = False
if options.webtoon:
self.color = True
else:
return None
self.color = self.isImageColor()
def saveToDir(self, targetdir):
try:
flags = []
filename = os.path.join(targetdir, os.path.splitext(self.filename)[0]) + '-KCC'
if not self.opt.forcecolor and not self.opt.forcepng:
self.image = self.image.convert('L')
if self.rotated:
flags.append('Rotated')
if self.noPV:
flags.append('NoPanelView')
else:
if self.noHPV:
flags.append('NoHorizontalPanelView')
if self.noVPV:
flags.append('NoVerticalPanelView')
if self.border:
flags.append('Margins-' + str(self.border[0]) + '-' + str(self.border[1]) + '-'
+ str(self.border[2]) + '-' + str(self.border[3]))
if self.fill != 'white':
flags.append('BlackFill')
if self.opt.quality == 2:
filename += '-HQ'
if self.opt.forcepng:
filename += '.png'
self.image.save(filename, 'PNG', optimize=1)
else:
filename += '.jpg'
self.image.save(filename, 'JPEG', optimize=1, quality=80)
return [md5Checksum(filename), flags]
except IOError as e:
raise RuntimeError('Cannot write image in directory %s: %s' % (targetdir, e))
def optimizeImage(self, gamma):
def autocontrastImage(self):
gamma = self.opt.gamma
if gamma < 0.1:
gamma = self.gamma
if self.gamma != 1.0 and self.color:
@@ -179,75 +186,65 @@ class ComicPage:
# Quantize is deprecated but new function call it internally anyway...
self.image = self.image.quantize(palette=palImg)
def calculateBorderPercent(self, x, img, isWidth):
if isWidth:
return int(round(float(x)/float(img.image.size[0]), 4) * 10000 * 1.5)
else:
return int(round(float(x)/float(img.image.size[1]), 4) * 10000 * 1.5)
def calculateBorder(self, sourceImage, isHQ=False):
if (isHQ and sourceImage.purge) or self.noPV:
self.border = [0, 0, 0, 0]
self.noPV = True
def calculateBorder(self):
if self.noPV:
self.border = [0.0, 0.0, 0.0, 0.0]
return
if self.fill == 'white':
# Only already saved files can have P mode. So we can break color quantization.
if sourceImage.image.mode == 'P':
sourceImage.image = sourceImage.image.convert('RGB')
border = ImageChops.invert(sourceImage.image).getbbox()
border = ImageChops.invert(self.image).getbbox()
else:
border = sourceImage.image.getbbox()
border = self.image.getbbox()
if self.opt.quality == 2:
multiplier = 1.0
else:
multiplier = 1.5
if border is not None:
if isHQ:
multiplier = 1.0
else:
multiplier = 1.5
self.border = [self.calculateBorderPercent(border[0], sourceImage, True),
self.calculateBorderPercent(border[1], sourceImage, False),
self.calculateBorderPercent((sourceImage.image.size[0] - border[2]), sourceImage, True),
self.calculateBorderPercent((sourceImage.image.size[1] - border[3]), sourceImage, False)]
if int((border[2] - border[0]) * multiplier) < self.size[0]:
self.border = [round(float(border[0])/float(self.image.size[0])*150, 3),
round(float(border[1])/float(self.image.size[1])*150, 3),
round(float(self.image.size[0]-border[2])/float(self.image.size[0])*150, 3),
round(float(self.image.size[1]-border[3])/float(self.image.size[1])*150, 3)]
if int((border[2] - border[0]) * multiplier) < self.size[0] + 10:
self.noHPV = True
if int((border[3] - border[1]) * multiplier) < self.size[1]:
if int((border[3] - border[1]) * multiplier) < self.size[1] + 10:
self.noVPV = True
else:
self.border = [0, 0, 0, 0]
self.border = [0.0, 0.0, 0.0, 0.0]
self.noHPV = True
self.noVPV = True
def resizeImage(self, upscale=False, stretch=False, bordersColor=None, qualityMode=0):
if bordersColor:
fill = bordersColor
def resizeImage(self):
if self.opt.bordersColor:
fill = self.opt.bordersColor
else:
fill = self.fill
# Set target size
if qualityMode == 0:
if self.opt.quality == 0:
size = (self.size[0], self.size[1])
elif qualityMode == 1 and not stretch and not upscale and self.image.size[0] <=\
elif self.opt.quality == 1 and not self.opt.stretch and not self.opt.upscale and self.image.size[0] <=\
self.size[0] and self.image.size[1] <= self.size[1]:
size = (self.size[0], self.size[1])
elif qualityMode == 1:
elif self.opt.quality == 1:
# Forcing upscale to make sure that margins will be not too big
if not stretch:
upscale = True
if not self.opt.stretch:
self.opt.upscale = True
size = (self.panelviewsize[0], self.panelviewsize[1])
elif qualityMode == 2 and not stretch and not upscale and self.image.size[0] <=\
elif self.opt.quality == 2 and not self.opt.stretch and not self.opt.upscale and self.image.size[0] <=\
self.size[0] and self.image.size[1] <= self.size[1]:
self.purge = True
return self.image
# HQ version will not be needed
self.noHQ = True
return
else:
self.hq = True
size = (self.panelviewsize[0], self.panelviewsize[1])
# If stretching is on - Resize without other considerations
if stretch:
if self.opt.stretch:
if self.image.size[0] <= size[0] and self.image.size[1] <= size[1]:
method = Image.BICUBIC
else:
method = Image.ANTIALIAS
method = Image.LANCZOS
self.image = self.image.resize(size, method)
return self.image
return
# If image is smaller than target resolution and upscale is off - Just expand it by adding margins
if self.image.size[0] <= size[0] and self.image.size[1] <= size[1] and not upscale:
if self.image.size[0] <= size[0] and self.image.size[1] <= size[1] and not self.opt.upscale:
borderw = int((size[0] - self.image.size[0]) / 2)
borderh = int((size[1] - self.image.size[1]) / 2)
# PV is disabled when source image is smaller than device screen and upscale is off
@@ -257,7 +254,7 @@ class ComicPage:
# Border can't be float so sometimes image might be 1px too small/large
if self.image.size[0] != size[0] or self.image.size[1] != size[1]:
self.image = ImageOps.fit(self.image, size, method=Image.BICUBIC, centering=(0.5, 0.5))
return self.image
return
# Otherwise - Upscale/Downscale
ratioDev = float(size[0]) / float(size[1])
if (float(self.image.size[0]) / float(self.image.size[1])) < ratioDev:
@@ -269,17 +266,17 @@ class ComicPage:
if self.image.size[0] <= size[0] and self.image.size[1] <= size[1]:
method = Image.BICUBIC
else:
method = Image.ANTIALIAS
method = Image.LANCZOS
self.image = ImageOps.fit(self.image, size, method=method, centering=(0.5, 0.5))
return self.image
return
def splitPage(self, targetdir, righttoleft=False, rotate=False):
def splitPage(self, targetdir):
width, height = self.image.size
dstwidth, dstheight = self.size
# Only split if origin is not oriented the same as target
if (width > height) != (dstwidth > dstheight):
if rotate:
self.image = self.image.rotate(90)
if self.opt.rotate:
self.image = self.image.rotate(90, Image.BICUBIC, True)
self.rotated = True
return None
else:
@@ -292,18 +289,18 @@ class ComicPage:
# Source is portrait and target is landscape, so split by the height
leftbox = (0, 0, width, int(height / 2))
rightbox = (0, int(height / 2), width, height)
filename = os.path.splitext(self.filename)
fileone = targetdir + '/' + filename[0] + '-A' + filename[1]
filetwo = targetdir + '/' + filename[0] + '-B' + filename[1]
filename = os.path.splitext(self.filename)[0]
fileone = targetdir + '/' + filename + '-AAA.png'
filetwo = targetdir + '/' + filename + '-BBB.png'
try:
if righttoleft:
if self.opt.righttoleft:
pageone = self.image.crop(rightbox)
pagetwo = self.image.crop(leftbox)
else:
pageone = self.image.crop(leftbox)
pagetwo = self.image.crop(rightbox)
pageone.save(fileone)
pagetwo.save(filetwo)
pageone.save(fileone, 'PNG', optimize=1)
pagetwo.save(filetwo, 'PNG', optimize=1)
except IOError as e:
raise RuntimeError('Cannot write image in directory %s: %s' % (targetdir, e))
return fileone, filetwo
@@ -364,7 +361,6 @@ class ComicPage:
else:
diff = pageNumberCut1
self.image = self.image.crop((0, 0, widthImg, heightImg - diff))
return self.image
def cropWhiteSpace(self):
if ImageChops.invert(self.image).getbbox() is not None:
@@ -400,7 +396,6 @@ class ComicPage:
diff += delta
diff -= delta
self.image = self.image.crop((0, 0, widthImg - diff, heightImg))
return self.image
def getImageHistogram(self, image):
histogram = image.histogram()
@@ -417,13 +412,16 @@ class ComicPage:
imageBoxB = ImageChops.invert(bw).getbbox()
if imageBoxA is None or imageBoxB is None:
surfaceB, surfaceW = 0, 0
diff = 0
else:
surfaceB = (imageBoxA[2] - imageBoxA[0]) * (imageBoxA[3] - imageBoxA[1])
surfaceW = (imageBoxB[2] - imageBoxB[0]) * (imageBoxB[3] - imageBoxB[1])
if surfaceW < surfaceB:
self.fill = 'white'
elif surfaceW > surfaceB:
self.fill = 'black'
diff = ((max(surfaceB, surfaceW) - min(surfaceB, surfaceW)) / min(surfaceB, surfaceW)) * 100
if diff > 0.5:
if surfaceW < surfaceB:
self.fill = 'white'
elif surfaceW > surfaceB:
self.fill = 'black'
else:
fill = 0
startY = 0
@@ -498,8 +496,8 @@ class Cover:
def processExternal(self):
self.image = self.image.convert('RGB')
self.image.thumbnail(self.options.profileData[1], Image.ANTIALIAS)
self.save(True)
self.image.thumbnail(self.options.profileData[1], Image.LANCZOS)
self.save()
def trim(self):
bg = Image.new(self.image.mode, self.image.size, self.image.getpixel((0, 0)))
@@ -511,15 +509,8 @@ class Cover:
else:
return self.image
def save(self, external=False):
if external:
source = self.options.remoteCovers[self.tomeNumber].split('/')[-1]
else:
source = self.source
def save(self):
try:
if os.path.splitext(source)[1].lower() == '.png':
self.image.save(self.target, "PNG", optimize=1)
else:
self.image.save(self.target, "JPEG", optimize=1)
self.image.save(self.target, "JPEG", optimize=1, quality=80)
except IOError:
raise RuntimeError('Failed to save cover')

172
kcc/metadata.py Normal file
View File

@@ -0,0 +1,172 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2013-2015 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
from xml.dom.minidom import parse, Document
from re import compile
from zipfile import is_zipfile, ZipFile, ZIP_DEFLATED
from subprocess import STDOUT, PIPE
from psutil import Popen
from tempfile import mkdtemp
from shutil import rmtree
from .shared import removeFromZIP, check7ZFile as is_7zfile
from . import rarfile
class MetadataParser:
def __init__(self, source):
self.source = source
self.data = {'Series': '',
'Volume': '',
'Number': '',
'Writers': [],
'Pencillers': [],
'Inkers': [],
'Colorists': [],
'Summary': '',
'MUid': '',
'Bookmarks': []}
self.rawdata = None
self.compressor = None
if self.source.endswith('.xml'):
self.rawdata = parse(self.source)
self.parseXML()
else:
if is_zipfile(self.source):
self.compressor = 'zip'
with ZipFile(self.source) as zip_file:
for member in zip_file.namelist():
if member != 'ComicInfo.xml':
continue
with zip_file.open(member) as xml_file:
self.rawdata = parse(xml_file)
elif rarfile.is_rarfile(self.source):
self.compressor = 'rar'
with rarfile.RarFile(self.source) as rar_file:
for member in rar_file.namelist():
if member != 'ComicInfo.xml':
continue
with rar_file.open(member) as xml_file:
self.rawdata = parse(xml_file)
elif is_7zfile(self.source):
self.compressor = '7z'
workdir = mkdtemp('', 'KCC-')
tmpXML = os.path.join(workdir, 'ComicInfo.xml')
output = Popen('7za e "' + self.source + '" ComicInfo.xml -o"' + workdir + '"',
stdout=PIPE, stderr=STDOUT, shell=True)
extracted = False
for line in output.stdout:
if b"Everything is Ok" in line or b"No files to process" in line:
extracted = True
if not extracted:
rmtree(workdir)
raise OSError
if os.path.isfile(tmpXML):
self.rawdata = parse(tmpXML)
rmtree(workdir)
else:
raise OSError
if self.rawdata:
self.parseXML()
def parseXML(self):
if len(self.rawdata.getElementsByTagName('Series')) != 0:
self.data['Series'] = self.rawdata.getElementsByTagName('Series')[0].firstChild.nodeValue
if len(self.rawdata.getElementsByTagName('Volume')) != 0:
self.data['Volume'] = self.rawdata.getElementsByTagName('Volume')[0].firstChild.nodeValue
if len(self.rawdata.getElementsByTagName('Number')) != 0:
self.data['Number'] = self.rawdata.getElementsByTagName('Number')[0].firstChild.nodeValue
if len(self.rawdata.getElementsByTagName('Summary')) != 0:
self.data['Summary'] = self.rawdata.getElementsByTagName('Summary')[0].firstChild.nodeValue
for field in ['Writer', 'Penciller', 'Inker', 'Colorist']:
if len(self.rawdata.getElementsByTagName(field)) != 0:
for person in self.rawdata.getElementsByTagName(field)[0].firstChild.nodeValue.split(', '):
self.data[field + 's'].append(person)
self.data[field + 's'] = list(set(self.data[field + 's']))
self.data[field + 's'].sort()
if len(self.rawdata.getElementsByTagName('ScanInformation')) != 0:
coverId = compile('(MCD\\()(\\d+)(\\))')\
.search(self.rawdata.getElementsByTagName('ScanInformation')[0].firstChild.nodeValue)
if coverId:
self.data['MUid'] = coverId.group(2)
if len(self.rawdata.getElementsByTagName('Page')) != 0:
for page in self.rawdata.getElementsByTagName('Page'):
if 'Bookmark' in page.attributes and 'Image' in page.attributes:
self.data['Bookmarks'].append((int(page.attributes['Image'].value),
page.attributes['Bookmark'].value))
def saveXML(self):
if self.rawdata:
root = self.rawdata.getElementsByTagName('ComicInfo')[0]
for row in (['Series', self.data['Series']], ['Volume', self.data['Volume']],
['Number', self.data['Number']], ['Writer', ', '.join(self.data['Writers'])],
['Penciller', ', '.join(self.data['Pencillers'])], ['Inker', ', '.join(self.data['Inkers'])],
['Colorist', ', '.join(self.data['Colorists'])], ['Summary', self.data['Summary']],
['ScanInformation', 'MCD(' + self.data['MUid'] + ')' if self.data['MUid'] else '']):
if self.rawdata.getElementsByTagName(row[0]):
node = self.rawdata.getElementsByTagName(row[0])[0]
if row[1]:
node.firstChild.replaceWholeText(row[1])
else:
root.removeChild(node)
elif row[1]:
main = self.rawdata.createElement(row[0])
root.appendChild(main)
text = self.rawdata.createTextNode(row[1])
main.appendChild(text)
else:
doc = Document()
root = doc.createElement('ComicInfo')
root.setAttribute('xmlns:xsd', 'http://www.w3.org/2001/XMLSchema')
root.setAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance')
doc.appendChild(root)
for row in (['Series', self.data['Series']], ['Volume', self.data['Volume']],
['Number', self.data['Number']], ['Writer', ', '.join(self.data['Writers'])],
['Penciller', ', '.join(self.data['Pencillers'])], ['Inker', ', '.join(self.data['Inkers'])],
['Colorist', ', '.join(self.data['Colorists'])], ['Summary', self.data['Summary']],
['ScanInformation', 'MCD(' + self.data['MUid'] + ')' if self.data['MUid'] else '']):
if row[1]:
main = doc.createElement(row[0])
root.appendChild(main)
text = doc.createTextNode(row[1])
main.appendChild(text)
self.rawdata = doc
if self.source.endswith('.xml'):
with open(self.source, 'w', encoding='utf-8') as f:
self.rawdata.writexml(f, encoding='utf-8')
else:
workdir = mkdtemp('', 'KCC-')
tmpXML = os.path.join(workdir, 'ComicInfo.xml')
with open(tmpXML, 'w', encoding='utf-8') as f:
self.rawdata.writexml(f, encoding='utf-8')
if is_zipfile(self.source):
removeFromZIP(self.source, 'ComicInfo.xml')
with ZipFile(self.source, mode='a', compression=ZIP_DEFLATED) as zip_file:
zip_file.write(tmpXML, arcname=tmpXML.split(os.sep)[-1])
elif rarfile.is_rarfile(self.source):
raise NotImplementedError
elif is_7zfile(self.source):
output = Popen('7za a "' + self.source + '" "' + tmpXML + '"', stdout=PIPE, stderr=STDOUT, shell=True)
extracted = False
for line in output.stdout:
if b"Everything is Ok" in line:
extracted = True
if not extracted:
rmtree(workdir)
raise OSError
rmtree(workdir)

View File

@@ -1,5 +1,5 @@
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
# Copyright (c) 2013-2014 Pawel Jastrzebski <pawelj@iosphe.re>
# Copyright (c) 2013-2015 Pawel Jastrzebski <pawelj@iosphe.re>
#
# Based upon the code snippet by Ned Batchelder
# (http://nedbatchelder.com/blog/200712/extracting_jpgs_from_pdfs.html)
@@ -19,10 +19,6 @@
# PERFORMANCE OF THIS SOFTWARE.
#
__license__ = 'ISC'
__copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>'
__docformat__ = 'restructuredtext en'
import os
from random import choice
from string import ascii_uppercase, digits
@@ -33,7 +29,7 @@ class PdfJpgExtract:
self.origFileName = origFileName
self.filename = os.path.splitext(origFileName)
# noinspection PyUnusedLocal
self.path = self.filename[0] + "-KCC-TMP-" + ''.join(choice(ascii_uppercase + digits) for x in range(3))
self.path = self.filename[0] + "-KCC-" + ''.join(choice(ascii_uppercase + digits) for x in range(3))
def getPath(self):
return self.path

View File

@@ -1,6 +1,6 @@
# rarfile.py
#
# Copyright (c) 2005-2013 Marko Kreen <markokr@gmail.com>
# Copyright (c) 2005-2014 Marko Kreen <markokr@gmail.com>
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
@@ -74,7 +74,7 @@ For more details, refer to source.
"""
__version__ = '2.6'
__version__ = '2.7-kcc'
# export only interesting items
__all__ = ['is_rarfile', 'RarInfo', 'RarFile', 'RarExtFile']
@@ -178,8 +178,25 @@ EXTRACT_ARGS = ('x', '-y', '-idq')
#: args for testrar()
TEST_ARGS = ('t', '-idq')
#
# Allow use of tool that is not compatible with unrar.
#
# By default use 'bsdtar' which is 'tar' program that
# sits on top of libarchive.
#
# Problems with libarchive RAR backend:
# - Does not support solid archives.
# - Does not support password-protected archives.
#
ALT_TOOL = 'bsdtar'
ALT_OPEN_ARGS = ('-x', '--to-stdout', '-f')
ALT_EXTRACT_ARGS = ('-x', '-f')
ALT_TEST_ARGS = ('-t', '-f')
ALT_CHECK_ARGS = ('--help',)
#: whether to speed up decompression by using tmp archive
USE_EXTRACT_HACK = 1
USE_EXTRACT_HACK = 0
#: limit the filesize for tmp archive usage
HACK_SIZE_LIMIT = 20*1024*1024
@@ -278,6 +295,7 @@ RAR_M5 = 0x35
##
RAR_ID = bytes("Rar!\x1a\x07\x00", 'ascii')
RAR5_ID = bytes("Rar!\x1a\x07\x01", 'ascii')
ZERO = bytes("\0", 'ascii')
EMPTY = bytes("", 'ascii')
@@ -336,6 +354,8 @@ class RarUnknownError(RarExecError):
"""Unknown exit code"""
class RarSignalExit(RarExecError):
"""Unrar exited with signal"""
class RarCannotExec(RarExecError):
"""Executable not found."""
def is_rarfile(xfile):
@@ -343,7 +363,10 @@ def is_rarfile(xfile):
fd = XFile(xfile)
buf = fd.read(len(RAR_ID))
fd.close()
return buf == RAR_ID
if buf == RAR_ID or buf == RAR5_ID:
return True
else:
return False
class RarInfo(object):
@@ -693,10 +716,7 @@ class RarFile(object):
"""Let 'unrar' test the archive.
"""
cmd = [UNRAR_TOOL] + list(TEST_ARGS)
if self._password is not None:
cmd.append('-p' + self._password)
else:
cmd.append('-p-')
add_password_arg(cmd, self._password)
cmd.append(self.rarfile)
p = custom_popen(cmd)
output = p.communicate()[0]
@@ -769,7 +789,7 @@ class RarFile(object):
fd = XFile(self.rarfile)
self._fd = fd
id = fd.read(len(RAR_ID))
if id != RAR_ID:
if id != RAR_ID and id != RAR5_ID:
raise NotRarFile("Not a Rar archive: "+self.rarfile)
volume = 0 # first vol (.rar) is 0
@@ -1172,8 +1192,7 @@ class RarFile(object):
if is_filelike(rarfile):
raise ValueError("Cannot use unrar directly on memory buffer")
cmd = [UNRAR_TOOL] + list(OPEN_ARGS)
if psw is not None:
cmd.append("-p" + psw)
add_password_arg(cmd, psw)
cmd.append(rarfile)
# not giving filename avoids encoding related problems
@@ -1205,10 +1224,7 @@ class RarFile(object):
# pasoword
psw = psw or self._password
if psw is not None:
cmd.append('-p' + psw)
else:
cmd.append('-p-')
add_password_arg(cmd, psw)
# rar file
cmd.append(self.rarfile)
@@ -1830,10 +1846,7 @@ def rar_decompress(vers, meth, data, declen=0, flags=0, crc=0, psw=None, salt=No
tmpf.close()
cmd = [UNRAR_TOOL] + list(OPEN_ARGS)
if psw is not None and (flags & RAR_FILE_PASSWORD):
cmd.append("-p" + psw)
else:
cmd.append("-p-")
add_password_arg(cmd, psw, (flags & RAR_FILE_PASSWORD))
cmd.append(tmpname)
p = custom_popen(cmd)
@@ -1902,10 +1915,27 @@ def custom_popen(cmd):
except OSError:
ex = sys.exc_info()[1]
if ex.errno == errno.ENOENT:
raise RarExecError("Unrar not installed? (rarfile.UNRAR_TOOL=%r)" % UNRAR_TOOL)
raise RarCannotExec("Unrar not installed? (rarfile.UNRAR_TOOL=%r)" % UNRAR_TOOL)
raise
return p
def custom_check(cmd, ignore_retcode=False):
"""Run command, collect output, raise error if needed."""
p = custom_popen(cmd)
out, err = p.communicate()
if p.returncode and not ignore_retcode:
raise RarExecError("Check-run failed")
return out
def add_password_arg(cmd, psw, required=False):
"""Append password switch to commandline."""
if UNRAR_TOOL == ALT_TOOL:
return
if psw is not None:
cmd.append('-p' + psw)
else:
cmd.append('-p-')
def check_returncode(p, out):
"""Raise exception according to unrar exit code"""
@@ -1920,6 +1950,8 @@ def check_returncode(p, out):
RarWarning, RarFatalError, RarCRCError, RarLockedArchiveError,
RarWriteError, RarOpenError, RarUserError, RarMemoryError,
RarCreateError, RarNoFilesError] # codes from rar.txt
if UNRAR_TOOL == ALT_TOOL:
errmap = [None]
if code > 0 and code < len(errmap):
exc = errmap[code]
elif code == 255:
@@ -1936,3 +1968,24 @@ def check_returncode(p, out):
msg = "%s [%d]" % (exc.__doc__, p.returncode)
raise exc(msg)
#
# Check if unrar works
#
try:
# does UNRAR_TOOL work?
custom_check([UNRAR_TOOL], True)
except RarCannotExec:
try:
# does ALT_TOOL work?
custom_check([ALT_TOOL] + list(ALT_CHECK_ARGS), True)
# replace config
UNRAR_TOOL = ALT_TOOL
OPEN_ARGS = ALT_OPEN_ARGS
EXTRACT_ARGS = ALT_EXTRACT_ARGS
TEST_ARGS = ALT_TEST_ARGS
except RarCannotExec:
# no usable tool, only uncompressed archives work
pass

View File

@@ -1,5 +1,5 @@
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
# Copyright (c) 2013-2014 Pawel Jastrzebski <pawelj@iosphe.re>
# Copyright (c) 2013-2015 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
@@ -16,33 +16,58 @@
# PERFORMANCE OF THIS SOFTWARE.
#
__license__ = 'ISC'
__copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>'
__docformat__ = 'restructuredtext en'
import os
from hashlib import md5
from html.parser import HTMLParser
from distutils.version import StrictVersion
from time import sleep
from shutil import rmtree, move
from tempfile import mkdtemp
from zipfile import ZipFile, ZIP_DEFLATED
from re import split
try:
from scandir import walk
except ImportError:
walk = None
class HTMLStripper(HTMLParser):
def __init__(self):
HTMLParser.__init__(self)
self.reset()
self.strict = False
self.convert_charrefs = True
self.fed = []
def handle_data(self, d):
self.fed.append(d)
def get_data(self):
return ''.join(self.fed)
def getImageFileName(imgfile):
filename = os.path.splitext(imgfile)
if filename[0].startswith('.') or\
(filename[1].lower() != '.png' and
filename[1].lower() != '.jpg' and
filename[1].lower() != '.gif' and
filename[1].lower() != '.tif' and
filename[1].lower() != '.tiff' and
filename[1].lower() != '.bmp' and
filename[1].lower() != '.jpeg'):
name, ext = os.path.splitext(imgfile)
ext = ext.lower()
if name.startswith('.') or (ext != '.png' and ext != '.jpg' and ext != '.jpeg' and ext != '.gif'):
return None
return filename
return [name, ext]
def walkSort(dirnames, filenames):
convert = lambda text: int(text) if text.isdigit() else text
alphanum_key = lambda key: [convert(c) for c in split('([0-9]+)', key)]
dirnames.sort(key=lambda name: alphanum_key(name.lower()))
filenames.sort(key=lambda name: alphanum_key(name.lower()))
return dirnames, filenames
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 os.walk(some_dir):
for root, dirs, files in walk(some_dir):
dirs, files = walkSort(dirs, files)
yield root, dirs, files
num_sep_this = root.count(os.path.sep)
if num_sep + level <= num_sep_this:
@@ -58,3 +83,75 @@ def md5Checksum(filePath):
break
m.update(data)
return m.hexdigest()
def check7ZFile(filePath):
with open(filePath, 'rb') as fh:
header = fh.read(6)
return header == b"7z\xbc\xaf'\x1c"
def saferReplace(old, new):
for x in range(5):
try:
os.replace(old, new)
except PermissionError:
sleep(5)
else:
break
else:
raise PermissionError
def removeFromZIP(zipfname, *filenames):
tempdir = mkdtemp('', 'KCC-')
try:
tempname = os.path.join(tempdir, 'KCC.zip')
with ZipFile(zipfname, 'r') as zipread:
with ZipFile(tempname, 'w', compression=ZIP_DEFLATED) as zipwrite:
for item in zipread.infolist():
if item.filename not in filenames:
zipwrite.writestr(item, zipread.read(item.filename))
move(tempname, zipfname)
finally:
rmtree(tempdir)
# noinspection PyUnresolvedReferences
def dependencyCheck(level):
missing = []
if level > 2:
try:
from PyQt5.QtCore import qVersion as qtVersion
if StrictVersion('5.2.0') > StrictVersion(qtVersion()):
missing.append('PyQt 5.2.0+')
except ImportError:
missing.append('PyQt 5.2.0+')
if level > 1:
try:
from psutil import __version__ as psutilVersion
if StrictVersion('3.0.0') > StrictVersion(psutilVersion):
missing.append('psutil 3.0.0+')
except ImportError:
missing.append('psutil 3.0.0+')
try:
from slugify import __version__ as slugifyVersion
if StrictVersion('1.1.2') > StrictVersion(slugifyVersion):
missing.append('python-slugify 1.1.2+')
except ImportError:
missing.append('python-slugify 1.1.2+')
try:
from PIL import PILLOW_VERSION as pillowVersion
if StrictVersion('2.8.2') > StrictVersion(pillowVersion):
missing.append('Pillow 2.8.2+')
except ImportError:
missing.append('Pillow 2.8.2+')
try:
from scandir import __version__ as scandirVersion
if StrictVersion('1.1') > StrictVersion(scandirVersion):
missing.append('scandir 1.1+')
except ImportError:
missing.append('scandir 1.1+')
if len(missing) > 0:
print('ERROR: ' + ', '.join(missing) + ' is not installed!')
exit(1)

BIN
other/7za Executable file

Binary file not shown.

BIN
other/7za.exe Normal file

Binary file not shown.

BIN
other/UnRAR.exe Normal file

Binary file not shown.

BIN
other/unrar Executable file

Binary file not shown.

170
setup.py
View File

@@ -1,24 +1,32 @@
#!/usr/bin/env python3
"""
cx_Freeze/py2app build script for KCC.
Usage (Mac OS X):
python setup.py py2app
pip/py2exe/py2app build script for KCC.
Usage (Windows):
python setup.py py2exe
py -3.4 setup.py py2exe
Usage (Linux):
python3 setup.py make_pyz or python3 setup.py install
Usage (Mac OS X):
python3 setup.py py2app
"""
from sys import platform, version_info
from sys import platform, version_info, argv
from kcc import __version__
if version_info[0] != 3:
print('ERROR: This is Python 3 script!')
exit(1)
NAME = "KindleComicConverter"
VERSION = "4.2.1"
MAIN = "kcc.py"
NAME = 'KindleComicConverter'
VERSION = __version__
MAIN = 'kcc.py'
extra_options = {}
if platform == "darwin":
# noinspection PyUnresolvedReferences
if platform == 'darwin':
from setuptools import setup
from os import chmod, makedirs
from shutil import copyfile
extra_options = dict(
setup_requires=['py2app'],
app=[MAIN],
@@ -26,17 +34,14 @@ if platform == "darwin":
py2app=dict(
argv_emulation=True,
iconfile='icons/comic2ebook.icns',
includes=['PIL', 'sip', 'PyQt5', 'PyQt5.QtCore', 'PyQt5.QtGui', 'PyQt5.QtNetwork', 'PyQt5.QtWidgets',
'PyQt5.QtPrintSupport'],
includes=['sip', 'PyQt5.QtPrintSupport'],
resources=['LICENSE.txt', 'other/qt.conf', 'other/Additional-LICENSE.txt', 'other/unrar', 'other/7za'],
plist=dict(
CFBundleName=NAME,
CFBundleShortVersionString=VERSION,
CFBundleGetInfoString=NAME + " " + VERSION +
", written 2012-2014 by Ciro Mattia Gonano and Pawel Jastrzebski",
CFBundleGetInfoString=NAME + ' ' + VERSION +
', written 2012-2015 by Ciro Mattia Gonano and Pawel Jastrzebski',
CFBundleExecutable=NAME,
CFBundleIdentifier='com.github.ciromattia.kcc',
CFBundleSignature='dplt',
CFBundleDocumentTypes=[
dict(
CFBundleTypeExtensions=['cbz', 'cbr', 'cb7', 'zip', 'rar', '7z', 'pdf'],
@@ -47,90 +52,111 @@ if platform == "darwin":
],
LSMinimumSystemVersion='10.8.0',
LSEnvironment=dict(
PATH='/usr/local/bin:/usr/bin:/bin'
PATH='./../Resources:/usr/local/bin:/usr/bin:/bin'
),
NSHumanReadableCopyright='ISC License (ISCL)'
)
)
)
)
elif platform == "win32":
elif platform == 'win32':
# noinspection PyUnresolvedReferences
import py2exe
import platform as arch
from platform import architecture
from distutils.core import setup
if arch.architecture()[0] == '64bit':
if architecture()[0] == '64bit':
suffix = '_64'
else:
suffix = ''
additional_files = [('imageformats', ['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 +
additional_files = [('platforms', ['C:\Python34' + suffix +
'\Lib\site-packages\PyQt5\plugins\platforms\qwindows.dll']),
('', ['LICENSE.txt',
'other\\7za.exe',
'other\\UnRAR.exe',
'other\\Additional-LICENSE.txt',
'other\\7za.exe',
'C:\Python34' + suffix + '\Lib\site-packages\PyQt5\libGLESv2.dll',
'C:\Python34' + suffix + '\Lib\site-packages\PyQt5\libEGL.dll'])]
extra_options = dict(
options={'py2exe': {"bundle_files": 2,
"dll_excludes": ["tcl85.dll", "tk85.dll"],
"dist_dir": "dist" + suffix,
"compressed": True,
"includes": ["sip"],
"excludes": ["tkinter"],
"optimize": 2}},
windows=[{"script": "kcc.py",
"dest_base": "KCC",
"version": VERSION,
"copyright": "Ciro Mattia Gonano, Pawel Jastrzebski © 2014",
"legal_copyright": "ISC License (ISCL)",
"product_version": VERSION,
"product_name": "Kindle Comic Converter",
"file_description": "Kindle Comic Converter",
"icon_resources": [(1, "icons\comic2ebook.ico")]}],
options={'py2exe': {'bundle_files': 1,
'dist_dir': 'dist' + suffix,
'compressed': True,
'includes': ['sip'],
'excludes': ['tkinter'],
'optimize': 2}},
windows=[{'script': MAIN,
'dest_base': 'KCC',
'version': VERSION,
'copyright': 'Ciro Mattia Gonano, Pawel Jastrzebski © 2012-2015',
'legal_copyright': 'ISC License (ISCL)',
'product_version': VERSION,
'product_name': 'Kindle Comic Converter',
'file_description': 'Kindle Comic Converter',
'icon_resources': [(1, 'icons\comic2ebook.ico')]}],
zipfile=None,
data_files=additional_files)
else:
print('Please use setup.sh to build Linux package.')
exit()
if argv[1] == 'make_pyz':
from os import system
script = '''
cp kcc.py __main__.py
zip kcc.zip __main__.py kcc/*.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 kcc/*.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 kcc/*.py
echo "#!/usr/bin/env python3" > kcc-c2p-bin
cat kcc-c2p.zip >> kcc-c2p-bin
chmod +x kcc-c2p-bin
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 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
'''
system("bash -c '%s'" % script)
exit(0)
else:
from setuptools import setup
from os import makedirs
from shutil import copyfile
makedirs('build/_scripts/', exist_ok=True)
copyfile('kcc.py', 'build/_scripts/kcc')
copyfile('kcc-c2e.py', 'build/_scripts/kcc-c2e')
copyfile('kcc-c2p.py', 'build/_scripts/kcc-c2p')
extra_options = dict(
scripts=['build/_scripts/kcc', 'build/_scripts/kcc-c2e', 'build/_scripts/kcc-c2p'],
packages=['kcc'],
install_requires=[
'Pillow>=2.8.2',
'psutil>=3.0.0',
'python-slugify>=1.1.2',
'scandir>=1.1.0',
],
zip_safe=False,
)
#noinspection PyUnboundLocalVariable
setup(
name=NAME,
version=VERSION,
author="Ciro Mattia Gonano, Pawel Jastrzebski",
author_email="ciromattia@gmail.com, pawelj@iosphe.re",
description="Kindle Comic Converter",
license="ISC License (ISCL)",
keywords="kindle comic mobipocket mobi cbz cbr manga",
url="http://github.com/ciromattia/kcc",
author='Ciro Mattia Gonano, Pawel Jastrzebski',
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',
url='http://github.com/ciromattia/kcc',
**extra_options
)
if platform == "darwin":
from os import chmod, makedirs
from shutil import copyfile
makedirs('dist/' + NAME + '.app/Contents/PlugIns/platforms')
if platform == 'darwin':
makedirs('dist/' + NAME + '.app/Contents/PlugIns/platforms', exist_ok=True)
copyfile('other/libqcocoa.dylib', 'dist/' + NAME + '.app/Contents/PlugIns/platforms/libqcocoa.dylib')
chmod('dist/' + NAME + '.app/Contents/Resources/unrar', 0o777)
chmod('dist/' + NAME + '.app/Contents/Resources/7za', 0o777)
chmod('dist/' + NAME + '.app/Contents/Resources/7za', 0o777)

View File

@@ -1,25 +0,0 @@
#!/bin/bash
# Linux Python package build script
VERSION="4.2.1"
cp kcc.py __main__.py
zip kcc.zip __main__.py kcc/*.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 kcc/*.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 kcc/*.py
echo "#!/usr/bin/env python3" > kcc-c2p-bin
cat kcc-c2p.zip >> kcc-c2p-bin
chmod +x kcc-c2p-bin
tar --xform s:^.*/:: --xform s/kcc-bin/kcc/ --xform s/kcc-c2p-bin/kcc-c2p/ --xform s/kcc-c2e-bin/kcc-c2e/ --xform s/comic2ebook/kcc/ -czf KindleComicConverter_linux_$VERSION.tar.gz kcc-bin kcc-c2e-bin kcc-c2p-bin LICENSE.txt icons/comic2ebook.png
rm __main__.py kcc.zip kcc-c2e.zip kcc-c2p.zip kcc-bin kcc-c2e-bin kcc-c2p-bin