mirror of
https://github.com/ciromattia/kcc
synced 2026-04-17 22:48:53 +00:00
Compare commits
47 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
34e2af3389 | ||
|
|
5ecddaceab | ||
|
|
fe554c20aa | ||
|
|
6acf1a1802 | ||
|
|
ac81a6be4b | ||
|
|
829a5f25e7 | ||
|
|
a695a4c151 | ||
|
|
7c0b78350d | ||
|
|
aa978ab246 | ||
|
|
7524c50657 | ||
|
|
9d8663a925 | ||
|
|
08ed304f8e | ||
|
|
658d2f3281 | ||
|
|
f44bf5993e | ||
|
|
458c28281f | ||
|
|
968a1afa1d | ||
|
|
2c875673bd | ||
|
|
1a0be83d63 | ||
|
|
36a7dc49ec | ||
|
|
40d1ae63da | ||
|
|
3d3621c6ec | ||
|
|
d77f04a84e | ||
|
|
ec51d6fc51 | ||
|
|
b7861d9d9e | ||
|
|
0b4503af21 | ||
|
|
437ffb9b10 | ||
|
|
066d1401bd | ||
|
|
9babe68d2a | ||
|
|
67de77538c | ||
|
|
c3e950f2ec | ||
|
|
ac2934aba2 | ||
|
|
a5064a0c0a | ||
|
|
2d712e796d | ||
|
|
cc3da40fd7 | ||
|
|
a53c272bd0 | ||
|
|
6526b139fd | ||
|
|
283d6101cd | ||
|
|
02dab3c6ee | ||
|
|
1895aa127d | ||
|
|
c01ff83fce | ||
|
|
4b670f3754 | ||
|
|
23b1560fa2 | ||
|
|
62350608dc | ||
|
|
8048b91fa8 | ||
|
|
2e9b3389e4 | ||
|
|
40e1ab4cf3 | ||
|
|
d2c12c89e6 |
8
.gitignore
vendored
8
.gitignore
vendored
@@ -1,17 +1,15 @@
|
|||||||
*.pyc
|
*.pyc
|
||||||
*.cbz
|
*.cbz
|
||||||
*.cbr
|
*.cbr
|
||||||
|
*.spec
|
||||||
.idea
|
.idea
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
.python-version
|
||||||
Thumbs.db
|
Thumbs.db
|
||||||
dist
|
dist
|
||||||
Output
|
Output
|
||||||
test
|
|
||||||
solaio
|
|
||||||
kindlegen*
|
kindlegen*
|
||||||
*.spec
|
|
||||||
setup.bat
|
setup.bat
|
||||||
setup.sh
|
|
||||||
kindlecomicconverter/sentry.py
|
kindlecomicconverter/sentry.py
|
||||||
build/
|
build/
|
||||||
.python-version
|
KindleComicConverter.egg-info/
|
||||||
|
|||||||
46
.travis.yml
Normal file
46
.travis.yml
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- os: linux
|
||||||
|
language: python
|
||||||
|
python: 3.6
|
||||||
|
dist: trusty
|
||||||
|
sudo: required
|
||||||
|
- os: osx
|
||||||
|
language: generic
|
||||||
|
osx_image: xcode6.4
|
||||||
|
|
||||||
|
before_install:
|
||||||
|
- if [ "$TRAVIS_OS_NAME" == "linux" ] ; then sudo apt-get -y install ruby ruby-dev ; fi
|
||||||
|
- if [ "$TRAVIS_OS_NAME" == "linux" ] ; then pip install --upgrade pip setuptools wheel ; fi
|
||||||
|
- if [ "$TRAVIS_OS_NAME" == "linux" ] ; then openssl aes-256-cbc -K $encrypted_a95564d8ff0d_key -iv $encrypted_a95564d8ff0d_iv -in other/linux/sentry.py.enc -out kindlecomicconverter/sentry.py -d ; fi
|
||||||
|
- if [ "$TRAVIS_OS_NAME" == "osx" ] ; then brew update ; fi
|
||||||
|
- if [ "$TRAVIS_OS_NAME" == "osx" ] ; then brew install python3 ; fi
|
||||||
|
- if [ "$TRAVIS_OS_NAME" == "osx" ] ; then travis_wait 30 brew upgrade node ; fi
|
||||||
|
- if [ "$TRAVIS_OS_NAME" == "osx" ] ; then pip3 install --upgrade pip setuptools wheel ; fi
|
||||||
|
- if [ "$TRAVIS_OS_NAME" == "osx" ] ; then openssl aes-256-cbc -K $encrypted_a95564d8ff0d_key -iv $encrypted_a95564d8ff0d_iv -in other/osx/sentry.py.enc -out kindlecomicconverter/sentry.py -d ; fi
|
||||||
|
|
||||||
|
install:
|
||||||
|
- if [ "$TRAVIS_OS_NAME" == "linux" ] ; then pip install -r requirements.txt ; fi
|
||||||
|
- if [ "$TRAVIS_OS_NAME" == "linux" ] ; then pip install certifi PyInstaller ; fi
|
||||||
|
- if [ "$TRAVIS_OS_NAME" == "linux" ] ; then gem install fpm ; fi
|
||||||
|
- if [ "$TRAVIS_OS_NAME" == "osx" ] ; then pip3 install -r requirements.txt ; fi
|
||||||
|
- if [ "$TRAVIS_OS_NAME" == "osx" ] ; then pip3 install certifi PyInstaller ; fi
|
||||||
|
- if [ "$TRAVIS_OS_NAME" == "osx" ] ; then npm install -g appdmg ; fi
|
||||||
|
|
||||||
|
script: python3 setup.py build_binary
|
||||||
|
|
||||||
|
before_deploy:
|
||||||
|
- shopt -s extglob
|
||||||
|
- rm -r dist/!(*.deb|*.dmg)
|
||||||
|
|
||||||
|
deploy:
|
||||||
|
provider: s3
|
||||||
|
skip_cleanup: true
|
||||||
|
access_key_id: AKIAIQNL5R4FI4C4NJYQ
|
||||||
|
secret_access_key:
|
||||||
|
secure: X66hYplxB4QSueljwvDfamNH/MQmHjo3mCofBcaTHAr7n2fp+yd2NzD2yy9h8NbsL0LWwx9wtJa/jpkIE02ZDfi9NrMLvKKFazzdpiyTMN5Yh85lHHyD1XIOCZRd4igaZ+O8975tJAEaEOPS+PE9XGZcRBh+y/eSJ+fMEgohaJ1MtDFbQR7X1cEw3iqbjrV2rlghZNCk/9mZEfObzAEjQiSDpv5G0IuIPRvYg/BgZt8chHVAe03B6oqcBa7uCBCTlfHIiNh1MWtP0B3NNBq3dcu9QHOFri1YqoZKuaPVCf6TFQL/NW5dFihegev2t9IwFyaBxytiT8fBkgQhP0VX8cuCwBAfnQGIogAu0eLSPp+E6dB/7Cpt2GDCk39+As8WKqt9hCRHmrvYhPA1Mq9QyEgKy/TKKKfDby3qVTIqYOQYpuQ1B7sIU651L5A+hBvZ1dqWIUz25h0zqjjeSFrcfNnf1e4tkk0QJvvnKqz0xsVaJxA2p07VJMRn8SlZQIJ2GEbMDeB5jxYtf5JzXywChP9adlPNjLna9G8ScnGSU1f7ZhsBQUEgY5jBlnX1lveyl3DUe6NP+qOTyljLWYwjx3AF4Zg10LYSecRS6hnqAUrGRmibDCIYclUzlJkVyjKGJ9uEyrUiCp0P0IsAzE1XhPVAWEyGUcWWGJG+jgmohSk=
|
||||||
|
bucket: kcc-deploy
|
||||||
|
region: eu-central-1
|
||||||
|
local_dir: dist
|
||||||
|
on:
|
||||||
|
repo: AcidWeb/kcc
|
||||||
355
CHANGELOG.md
Normal file
355
CHANGELOG.md
Normal file
@@ -0,0 +1,355 @@
|
|||||||
|
# CHANGELOG
|
||||||
|
#### 5.4.4:
|
||||||
|
* Minor bug fixes
|
||||||
|
|
||||||
|
#### 5.4.3:
|
||||||
|
* Fixed conversion crash on Windows
|
||||||
|
|
||||||
|
#### 5.4.2:
|
||||||
|
* Added Kindle Oasis 2 profile
|
||||||
|
* Allowed metadata editor to edit directories
|
||||||
|
* Fixed image stretching when HQ Panel View option was enabled
|
||||||
|
* Fixed possible problem with directory sort order
|
||||||
|
|
||||||
|
#### 5.4.1:
|
||||||
|
* Minor bug fixes and tweaks
|
||||||
|
* Implemented new binary build pipeline
|
||||||
|
|
||||||
|
#### 5.4:
|
||||||
|
* Reimplemented high quality Panel View option
|
||||||
|
* Improved webtoon splitter
|
||||||
|
* Fixed page splitter
|
||||||
|
|
||||||
|
#### 5.3.1:
|
||||||
|
* Small increase of output quality
|
||||||
|
* Improved error reporting
|
||||||
|
* Internal changes and tweaks
|
||||||
|
|
||||||
|
#### 5.3:
|
||||||
|
* Vastly improved output compatibility for non-Kindle devices
|
||||||
|
* Enabled old pinch zoom for Kindle devices
|
||||||
|
* Re-enabled Panel View support for Kindle Keyboard
|
||||||
|
* Partially re-enabled OS X file association mechanism
|
||||||
|
* Fixed multiple smaller issues
|
||||||
|
|
||||||
|
#### 5.2.1:
|
||||||
|
* Improved directory parsing
|
||||||
|
* Tweaked margin detection algorithm
|
||||||
|
* Improved error reporting
|
||||||
|
|
||||||
|
#### 5.2:
|
||||||
|
* Added new Panel View options
|
||||||
|
* Implemented new margin detection algorithm
|
||||||
|
* Removed HQ Panel View mode
|
||||||
|
* Fixed multiple smaller issues
|
||||||
|
|
||||||
|
#### 5.1.3:
|
||||||
|
* Added Kobo Aura ONE profile
|
||||||
|
* Fixed few small bugs
|
||||||
|
|
||||||
|
#### 5.1.2:
|
||||||
|
* Fixed error reporting
|
||||||
|
|
||||||
|
#### 5.1.1:
|
||||||
|
* Fixed multiple GUI bugs
|
||||||
|
|
||||||
|
#### 5.1:
|
||||||
|
* GUI now can be resized and high DPI support was somewhat improved
|
||||||
|
* Added profile for Kindle Oasis
|
||||||
|
* Implemented new error reporting mechanism
|
||||||
|
* CLI version now support additional cropping options
|
||||||
|
* Fixed permission issues on Windows
|
||||||
|
* Fixed multiple smaller issues
|
||||||
|
|
||||||
|
#### 5.0.1:
|
||||||
|
* Fixed Panel View placement issues
|
||||||
|
* Decreased application startup time
|
||||||
|
* Fixed multiple smaller issues
|
||||||
|
|
||||||
|
#### 5.0:
|
||||||
|
* Major overhaul of internal mechanisms and GUI
|
||||||
|
* Added cover upload feature
|
||||||
|
* Tweaked Webtoon parsing mode
|
||||||
|
* Fixed multiple smaller issues
|
||||||
|
* Migrated build enviroment to PyInstaller
|
||||||
|
|
||||||
|
#### 4.6.5:
|
||||||
|
* Fixed multiple Windows and OS X issues
|
||||||
|
* Allowed Linux release to use older PyQT5 version
|
||||||
|
|
||||||
|
#### 4.6.4:
|
||||||
|
* Fixed multiple Windows specific problems
|
||||||
|
* Improved error handling
|
||||||
|
* Improved color detection algorithm
|
||||||
|
* New, slimmer OS X release
|
||||||
|
|
||||||
|
#### 4.6.3:
|
||||||
|
* Implemented remote bug reporting
|
||||||
|
* Minor bug fixes and GUI tweaks
|
||||||
|
|
||||||
|
#### 4.6.2:
|
||||||
|
* Fixed critical MOBI header bug
|
||||||
|
* Fixed metadata encoding error
|
||||||
|
|
||||||
|
#### 4.6.1:
|
||||||
|
* Fixed KEPUB TOC generator
|
||||||
|
* Added warning about too small input files
|
||||||
|
* ComicRack Summary metadata field is now parsed
|
||||||
|
* Small tweaks of KEPUB output
|
||||||
|
|
||||||
|
#### 4.6:
|
||||||
|
* KEPUB is now default output for all Kobo profiles
|
||||||
|
* EPUB output now produce fully valid EPUB 3.0.1
|
||||||
|
* Added profile for Kindle Paperwhite 3
|
||||||
|
* Dropped official support of all Kindle Fire models and Kindle for Android
|
||||||
|
* Other minor tweaks
|
||||||
|
|
||||||
|
#### 4.5.1:
|
||||||
|
* Added Kobo Glo HD profile
|
||||||
|
* Fixed RAR/CBR parsing anomalies
|
||||||
|
* Minor bug fixes and tweaks
|
||||||
|
|
||||||
|
#### 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
|
||||||
|
|
||||||
|
#### 4.4.1:
|
||||||
|
* Fixed problems with OSX GUI
|
||||||
|
* Added one missing DLL to Windows installer
|
||||||
|
|
||||||
|
#### 4.4:
|
||||||
|
* Improved speed and quality of conversion
|
||||||
|
* Added RAR5 support
|
||||||
|
* Dropped BMP and TIFF support
|
||||||
|
* Fixed some WebToon mode bugs
|
||||||
|
* Fixed CBR parsing on OSX
|
||||||
|
|
||||||
|
#### 4.3.1:
|
||||||
|
* Fixed Kindle Voyage profile
|
||||||
|
* Fixed some bugs in OS X release
|
||||||
|
* CLI version now support multiple input files at once
|
||||||
|
* Disabled MCB support
|
||||||
|
* Other minor tweaks
|
||||||
|
|
||||||
|
#### 4.3:
|
||||||
|
* Added profiles for Kindle Voyage and Kobo Aura H2O
|
||||||
|
* Added missing features to CLI version
|
||||||
|
* Other minor bug fixes
|
||||||
|
|
||||||
|
#### 4.2.1:
|
||||||
|
* Improved margin color detection
|
||||||
|
* Fixed random crashes of MOBI processing step
|
||||||
|
* Fixed resizing problems in high quality mode
|
||||||
|
* Fixed some MCD support bugs
|
||||||
|
* Default output format for Kindle DX is now CBZ
|
||||||
|
|
||||||
|
#### 4.2:
|
||||||
|
* Added [Manga Cover Database](http://manga.joentjuh.nl/) support
|
||||||
|
* Officially dropped Windows XP support
|
||||||
|
* Fixed _Other_ profile
|
||||||
|
* Fixed problems with page order on stock KOBO CBZ reader
|
||||||
|
* Many other small bug fixes and tweaks
|
||||||
|
|
||||||
|
#### 4.1:
|
||||||
|
* Thanks to code contributed by Kevin Hendricks speed of MOBI creation was greatly increased
|
||||||
|
* Improved performance on Windows
|
||||||
|
* Improved MOBI splitting and changed maximal size of output file
|
||||||
|
* Fixed _No optimization_ mode
|
||||||
|
* Multiple small tweaks nad minor bug fixes
|
||||||
|
|
||||||
|
#### 4.0.2:
|
||||||
|
* Fixed some Windows and OSX specific bugs
|
||||||
|
* Fixed problem with marigns when using HQ mode
|
||||||
|
|
||||||
|
#### 4.0.1:
|
||||||
|
* Fixed file lock problems that plagued some Windows users
|
||||||
|
* Fixed content server failing to start on Windows
|
||||||
|
* Improved performance of WebToon splitter
|
||||||
|
* Tweaked margin color detection
|
||||||
|
|
||||||
|
#### 4.0:
|
||||||
|
* 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
|
||||||
|
|
||||||
|
#### 3.7.2:
|
||||||
|
* Fixed problems with HQ mode
|
||||||
|
|
||||||
|
#### 3.7.1:
|
||||||
|
* Hotfixed Kobo profiles
|
||||||
|
|
||||||
|
#### 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
|
||||||
|
|
||||||
|
#### 3.6.2:
|
||||||
|
* Fixed previous PNG output fix
|
||||||
|
* Fixed Panel View anomalies
|
||||||
|
|
||||||
|
#### 3.6.1:
|
||||||
|
* Fixed PNG output
|
||||||
|
|
||||||
|
#### 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.5:
|
||||||
|
* Added simple content server - Converted files can be now delivered wireless
|
||||||
|
* Added proper Windows installer
|
||||||
|
* Improved multiprocessing speed
|
||||||
|
* GUI tweaks and minor bug fixes
|
||||||
|
|
||||||
|
#### 3.4:
|
||||||
|
* 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
|
||||||
|
* Margin color fill is now autodetected
|
||||||
|
* Created MOBI files are not longer marked as _Personal_ on newer Kindle models
|
||||||
|
* Layout of panels in Panel View mode is now automatically adjusted to content
|
||||||
|
* Fixed Kindle 2/DX/DXG profiles - no more blank pages
|
||||||
|
* All Kindle Fire profiles now support hiqh quality Panel View
|
||||||
|
* Added support of 7z/CB7 files
|
||||||
|
* Added Kindle Fire HDX profile
|
||||||
|
* Support for Virtual Panel View was removed
|
||||||
|
* Profiles for Kindle Keyboard, Touch and Non-Touch are now merged
|
||||||
|
* Windows release is now bundled with UnRAR and 7za
|
||||||
|
* Small 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.2.1:
|
||||||
|
* Hotfixed crash occurring on OS with Russian locale
|
||||||
|
|
||||||
|
#### 3.1:
|
||||||
|
* Added profile: Kindle for Android
|
||||||
|
* Add file/directory dialogs now support multiselect
|
||||||
|
* Many small fixes and tweaks
|
||||||
|
|
||||||
|
#### 3.0:
|
||||||
|
* New QT GUI
|
||||||
|
* Merge with AWKCC
|
||||||
|
* Added ultra quality mode
|
||||||
|
* Added support for custom width/height
|
||||||
|
* Added option to disable color conversion
|
||||||
|
|
||||||
|
#### 2.10:
|
||||||
|
* 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)
|
||||||
|
|
||||||
|
#### 2.9
|
||||||
|
* Added support for generating a plain CBZ (skipping all the EPUB/MOBI generation) (#45)
|
||||||
|
* Prevent output file overwriting the source one: if a duplicate name is detected, append _kcc to the name
|
||||||
|
* Rarfile library updated to 2.6
|
||||||
|
* Added GIF, TIFF and BMP to supported formats (#42)
|
||||||
|
* Filenames slugifications (#28, #31, #9, #8)
|
||||||
|
|
||||||
|
#### 2.8
|
||||||
|
* 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)
|
||||||
|
|
||||||
|
#### 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
|
||||||
|
|
||||||
|
#### 2.6
|
||||||
|
* Added --rotate option to rotate landscape images instead of splitting them (#16, #24)
|
||||||
|
* Added --output option to customize EPUB output dir/file (#22)
|
||||||
|
* Add rendition:layout and rendition:orientation EPUB meta tags (supported by new kindlegen 2.8)
|
||||||
|
* Fixed natural sorting for files (#18)
|
||||||
|
|
||||||
|
#### 2.5
|
||||||
|
* Added --black-borders option to set added borders black when page's ratio is not the device's one (#11).
|
||||||
|
* Fixes EPUB containing zipped itself (#10)
|
||||||
|
|
||||||
|
#### 2.4
|
||||||
|
* Use temporary directory as workdir (fixes converting from external volumes and zipfiles renaming)
|
||||||
|
* Fixed "add folders" from GUI.
|
||||||
|
|
||||||
|
#### 2.3
|
||||||
|
* Fixed win32 EPUB generation, folder handling, filenames with spaces and subfolders
|
||||||
|
|
||||||
|
#### 2.2:
|
||||||
|
* Added (valid!) EPUB 2.0 output
|
||||||
|
* Rename .zip files to .cbz to avoid overwriting
|
||||||
|
|
||||||
|
#### 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
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
ISC LICENSE
|
ISC LICENSE
|
||||||
|
|
||||||
Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
||||||
Copyright (c) 2013-2017 Paweł Jastrzębski <pawelj@iosphe.re>
|
Copyright (c) 2013-2018 Paweł Jastrzębski <pawelj@iosphe.re>
|
||||||
|
|
||||||
Permission to use, copy, modify, and/or distribute this software for
|
Permission to use, copy, modify, and/or distribute this software for
|
||||||
any purpose with or without fee is hereby granted, provided that the
|
any purpose with or without fee is hereby granted, provided that the
|
||||||
|
|||||||
1
MANIFEST.in
Normal file
1
MANIFEST.in
Normal file
@@ -0,0 +1 @@
|
|||||||
|
exclude kindlecomicconverter/sentry.py
|
||||||
381
README.md
381
README.md
@@ -1,4 +1,6 @@
|
|||||||
# KCC
|
# KCC
|
||||||
|
|
||||||
|
[](https://github.com/ciromattia/kcc/releases) [](https://pypi.python.org/pypi/KindleComicConverter) [](https://aur.archlinux.org/packages/kcc/)
|
||||||
|
|
||||||
**Kindle Comic Converter** is a Python app to convert comic/manga files or folders to EPUB, Panel View MOBI or E-Ink optimized CBZ.
|
**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
|
It was initially developed for Kindle but since version 4.6 it outputs valid EPUB 3.0 so _**despite its name, KCC is
|
||||||
@@ -17,32 +19,37 @@ If you can fix an open issue, fork & make a pull request.
|
|||||||
|
|
||||||
If you find **KCC** valuable you can consider donating to the authors:
|
If you find **KCC** valuable you can consider donating to the authors:
|
||||||
- Ciro Mattia Gonano:
|
- Ciro Mattia Gonano:
|
||||||
- [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=D8WNYNPBGDAS2)
|
- [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=D8WNYNPBGDAS2)
|
||||||
- [](http://flattr.com/thing/2260449/ciromattiakcc-on-GitHub)
|
- [](http://flattr.com/thing/2260449/ciromattiakcc-on-GitHub)
|
||||||
- Paweł Jastrzębski:
|
- Paweł Jastrzębski:
|
||||||
- [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=YTTJ4LK2JDHPS)
|
- [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=YTTJ4LK2JDHPS)
|
||||||
- Bitcoin: 1W15wwqsfd7wbaZ6wvSJf1LW1bz6q5L8b
|
- [](https://jastrzeb.ski/donate/)
|
||||||
|
|
||||||
## BINARY RELEASES
|
## BINARY RELEASES
|
||||||
You can find the latest released binary at the following links:
|
You can find the latest released binary at the following links:
|
||||||
- **Windows (64-bit only):** [http://kcc.iosphe.re/Windows/](http://kcc.iosphe.re/Windows/)
|
- **Windows (64-bit only):** [http://kcc.iosphe.re/Windows/](http://kcc.iosphe.re/Windows/)
|
||||||
- **Linux (Glibc 2.19+):** [http://kcc.iosphe.re/Linux/](http://kcc.iosphe.re/Linux/)
|
- **Linux (Glibc 2.19+):** [http://kcc.iosphe.re/Linux/](http://kcc.iosphe.re/Linux/)
|
||||||
- **OS X (10.9+):** [http://kcc.iosphe.re/OSX/](http://kcc.iosphe.re/OSX/)
|
- **OS X (10.10+):** [http://kcc.iosphe.re/OSX/](http://kcc.iosphe.re/OSX/)
|
||||||
|
|
||||||
|
## PYPI
|
||||||
|
**KCC** is also available on PyPI.
|
||||||
|
```
|
||||||
|
pip install KindleComicConverter
|
||||||
|
```
|
||||||
|
|
||||||
## DEPENDENCIES
|
## DEPENDENCIES
|
||||||
Following software is required to run Linux version of **KCC** and/or bare sources:
|
Following software is required to run Linux version of **KCC** and/or bare sources:
|
||||||
- Python 3.3+
|
- Python 3.3+
|
||||||
- [PyQt](https://pypi.python.org/pypi/PyQt5) 5.6.0+
|
- [PyQt5](https://pypi.python.org/pypi/PyQt5) 5.6.0+
|
||||||
- [Pillow](https://pypi.python.org/pypi/Pillow/) 3.2.0+
|
- [Pillow](https://pypi.python.org/pypi/Pillow/) 4.0.0+
|
||||||
- [psutil](https://pypi.python.org/pypi/psutil) 4.1.0+
|
- [psutil](https://pypi.python.org/pypi/psutil) 5.0.0+
|
||||||
- [python-slugify](https://pypi.python.org/pypi/python-slugify) 1.2.0+
|
- [python-slugify](https://pypi.python.org/pypi/python-slugify) 1.2.1+
|
||||||
- [raven](https://pypi.python.org/pypi/raven) 5.13.0+
|
- [raven](https://pypi.python.org/pypi/raven) 6.0.0+
|
||||||
- [scandir](https://pypi.python.org/pypi/scandir) 1.2.0+ _(needed only when using Python 3.3 or 3.4)_
|
|
||||||
|
|
||||||
On Debian based distributions these two commands should install all needed dependencies:
|
On Debian based distributions these two commands should install all needed dependencies:
|
||||||
```
|
```
|
||||||
sudo apt-get install python3 python3-dev python3-pip libpng-dev libjpeg-dev p7zip-full unrar
|
sudo apt-get install python3 python3-dev python3-pip libpng-dev libjpeg-dev p7zip-full unrar
|
||||||
sudo pip3 install --upgrade pillow python-slugify psutil scandir raven pyqt5
|
sudo pip3 install --upgrade pillow python-slugify psutil pyqt5 raven
|
||||||
```
|
```
|
||||||
|
|
||||||
### Optional dependencies
|
### Optional dependencies
|
||||||
@@ -60,12 +67,12 @@ sudo pip3 install --upgrade pillow python-slugify psutil scandir raven pyqt5
|
|||||||
|
|
||||||
## USAGE
|
## USAGE
|
||||||
|
|
||||||
Should be pretty self-explanatory. All options have detailed informations in tooltips.
|
Should be pretty self-explanatory. All options have detailed information in tooltips.
|
||||||
After completed conversion you should find ready file alongside the original input file (same directory).
|
After completed conversion, you should find ready file alongside the original input file (same directory).
|
||||||
|
|
||||||
Please check [our wiki](https://github.com/ciromattia/kcc/wiki/) for more details.
|
Please check [our wiki](https://github.com/ciromattia/kcc/wiki/) for more details.
|
||||||
|
|
||||||
CLI version of **KCC** is intended for power users. It is not idiot-proof like GUI :-)
|
CLI version of **KCC** is intended for power users. It allows using options that might not be compatible and decrease the quality of output.
|
||||||
|
|
||||||
### Standalone `kcc-c2e.py` usage:
|
### Standalone `kcc-c2e.py` usage:
|
||||||
|
|
||||||
@@ -75,10 +82,11 @@ Usage: kcc-c2e [options] comic_file|comic_folder
|
|||||||
Options:
|
Options:
|
||||||
MAIN:
|
MAIN:
|
||||||
-p PROFILE, --profile=PROFILE
|
-p PROFILE, --profile=PROFILE
|
||||||
Device profile (Available options: K1, K2, K3, K45,
|
Device profile (Available options: K1, K2, K34, K578,
|
||||||
KDX, KPW, KV, KoMT, KoG, KoGHD, KoA, KoAHD, KoAH2O,
|
KDX, KPW, KV, KO, KoMT, KoG, KoGHD, KoA, KoAHD, KoAH2O,
|
||||||
KoAO) [Default=KV]
|
KoAO) [Default=KV]
|
||||||
-m, --manga-style Manga style (right-to-left reading and splitting)
|
-m, --manga-style Manga style (right-to-left reading and splitting)
|
||||||
|
-q, --hq Try to increase the quality of magnification
|
||||||
-2, --two-panel Display two not four panels in Panel View mode
|
-2, --two-panel Display two not four panels in Panel View mode
|
||||||
-w, --webtoon Webtoon processing mode
|
-w, --webtoon Webtoon processing mode
|
||||||
|
|
||||||
@@ -137,7 +145,7 @@ Options:
|
|||||||
-m, --merge Combine every directory into a single image before splitting
|
-m, --merge Combine every directory into a single image before splitting
|
||||||
|
|
||||||
OTHER:
|
OTHER:
|
||||||
-d, --debug Create debug file for every splitted image
|
-d, --debug Create debug file for every split image
|
||||||
-h, --help Show this help message and exit
|
-h, --help Show this help message and exit
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -154,344 +162,15 @@ The app relies and includes the following scripts:
|
|||||||
- Icon is by **Nikolay Verin** ([http://ncrow.deviantart.com/](http://ncrow.deviantart.com/)) and released under [CC BY-NC-SA 3.0](http://creativecommons.org/licenses/by-nc-sa/3.0/) License.
|
- Icon is by **Nikolay Verin** ([http://ncrow.deviantart.com/](http://ncrow.deviantart.com/)) and released under [CC BY-NC-SA 3.0](http://creativecommons.org/licenses/by-nc-sa/3.0/) License.
|
||||||
|
|
||||||
## SAMPLE FILES CREATED BY KCC
|
## SAMPLE FILES CREATED BY KCC
|
||||||
|
* [Kindle Oasis 2](http://kcc.iosphe.re/Samples/Ubunchu!-KO.mobi)
|
||||||
* [Kindle Paperwhite 3 / Voyage / Oasis](http://kcc.iosphe.re/Samples/Ubunchu!-KV.mobi)
|
* [Kindle Paperwhite 3 / Voyage / Oasis](http://kcc.iosphe.re/Samples/Ubunchu!-KV.mobi)
|
||||||
* [Kindle Paperwhite 1 / 2](http://kcc.iosphe.re/Samples/Ubunchu!-KPW.mobi)
|
* [Kindle Paperwhite 1 / 2](http://kcc.iosphe.re/Samples/Ubunchu!-KPW.mobi)
|
||||||
* [Kindle](http://kcc.iosphe.re/Samples/Ubunchu!-K45.mobi)
|
* [Kindle](http://kcc.iosphe.re/Samples/Ubunchu!-K578.mobi)
|
||||||
* [Kobo Aura](http://kcc.iosphe.re/Samples/Ubunchu-KoA.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 HD](http://kcc.iosphe.re/Samples/Ubunchu-KoAHD.kepub.epub)
|
||||||
* [Kobo Aura H2O](http://kcc.iosphe.re/Samples/Ubunchu-KoAH2O.kepub.epub)
|
* [Kobo Aura H2O](http://kcc.iosphe.re/Samples/Ubunchu-KoAH2O.kepub.epub)
|
||||||
* [Kobo Aura ONE](http://kcc.iosphe.re/Samples/Ubunchu-KoAO.kepub.epub)
|
* [Kobo Aura ONE](http://kcc.iosphe.re/Samples/Ubunchu-KoAO.kepub.epub)
|
||||||
|
|
||||||
## CHANGELOG
|
|
||||||
####5.3:
|
|
||||||
* Vastly improved output compatibility for non-Kindle devices
|
|
||||||
* Enabled old pinch zoom for Kindle devices
|
|
||||||
* Re-enabled Panel View support for Kindle Keyboard
|
|
||||||
* Partially re-enabled OS X file association mechanism
|
|
||||||
* Fixed multiple smaller issues
|
|
||||||
|
|
||||||
####5.2.1:
|
|
||||||
* Improved directory parsing
|
|
||||||
* Tweaked margin detection algorithm
|
|
||||||
* Improved error reporting
|
|
||||||
|
|
||||||
####5.2:
|
|
||||||
* Added new Panel View options
|
|
||||||
* Implemented new margin detection algorithm
|
|
||||||
* Removed HQ Panel View mode
|
|
||||||
* Fixed multiple smaller issues
|
|
||||||
|
|
||||||
####5.1.3:
|
|
||||||
* Added Kobo Aura ONE profile
|
|
||||||
* Fixed few small bugs
|
|
||||||
|
|
||||||
####5.1.2:
|
|
||||||
* Fixed error reporting
|
|
||||||
|
|
||||||
####5.1.1:
|
|
||||||
* Fixed multiple GUI bugs
|
|
||||||
|
|
||||||
####5.1:
|
|
||||||
* GUI now can be resized and high DPI support was somewhat improved
|
|
||||||
* Added profile for Kindle Oasis
|
|
||||||
* Implemented new error reporting mechanism
|
|
||||||
* CLI version now support additional cropping options
|
|
||||||
* Fixed permission issues on Windows
|
|
||||||
* Fixed multiple smaller issues
|
|
||||||
|
|
||||||
####5.0.1:
|
|
||||||
* Fixed Panel View placement issues
|
|
||||||
* Decreased application startup time
|
|
||||||
* Fixed multiple smaller issues
|
|
||||||
|
|
||||||
####5.0:
|
|
||||||
* Major overhaul of internal mechanisms and GUI
|
|
||||||
* Added cover upload feature
|
|
||||||
* Tweaked Webtoon parsing mode
|
|
||||||
* Fixed multiple smaller issues
|
|
||||||
* Migrated build enviroment to PyInstaller
|
|
||||||
|
|
||||||
####4.6.5:
|
|
||||||
* Fixed multiple Windows and OS X issues
|
|
||||||
* Allowed Linux release to use older PyQT5 version
|
|
||||||
|
|
||||||
####4.6.4:
|
|
||||||
* Fixed multiple Windows specific problems
|
|
||||||
* Improved error handling
|
|
||||||
* Improved color detection algorithm
|
|
||||||
* New, slimmer OS X release
|
|
||||||
|
|
||||||
####4.6.3:
|
|
||||||
* Implemented remote bug reporting
|
|
||||||
* Minor bug fixes and GUI tweaks
|
|
||||||
|
|
||||||
####4.6.2:
|
|
||||||
* Fixed critical MOBI header bug
|
|
||||||
* Fixed metadata encoding error
|
|
||||||
|
|
||||||
####4.6.1:
|
|
||||||
* Fixed KEPUB TOC generator
|
|
||||||
* Added warning about too small input files
|
|
||||||
* ComicRack Summary metadata field is now parsed
|
|
||||||
* Small tweaks of KEPUB output
|
|
||||||
|
|
||||||
####4.6:
|
|
||||||
* KEPUB is now default output for all Kobo profiles
|
|
||||||
* EPUB output now produce fully valid EPUB 3.0.1
|
|
||||||
* Added profile for Kindle Paperwhite 3
|
|
||||||
* Dropped official support of all Kindle Fire models and Kindle for Android
|
|
||||||
* Other minor tweaks
|
|
||||||
|
|
||||||
####4.5.1:
|
|
||||||
* Added Kobo Glo HD profile
|
|
||||||
* Fixed RAR/CBR parsing anomalies
|
|
||||||
* Minor bug fixes and tweaks
|
|
||||||
|
|
||||||
####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
|
|
||||||
|
|
||||||
####4.4.1:
|
|
||||||
* Fixed problems with OSX GUI
|
|
||||||
* Added one missing DLL to Windows installer
|
|
||||||
|
|
||||||
####4.4:
|
|
||||||
* Improved speed and quality of conversion
|
|
||||||
* Added RAR5 support
|
|
||||||
* Dropped BMP and TIFF support
|
|
||||||
* Fixed some WebToon mode bugs
|
|
||||||
* Fixed CBR parsing on OSX
|
|
||||||
|
|
||||||
####4.3.1:
|
|
||||||
* Fixed Kindle Voyage profile
|
|
||||||
* Fixed some bugs in OS X release
|
|
||||||
* CLI version now support multiple input files at once
|
|
||||||
* Disabled MCB support
|
|
||||||
* Other minor tweaks
|
|
||||||
|
|
||||||
####4.3:
|
|
||||||
* Added profiles for Kindle Voyage and Kobo Aura H2O
|
|
||||||
* Added missing features to CLI version
|
|
||||||
* Other minor bug fixes
|
|
||||||
|
|
||||||
####4.2.1:
|
|
||||||
* Improved margin color detection
|
|
||||||
* Fixed random crashes of MOBI processing step
|
|
||||||
* Fixed resizing problems in high quality mode
|
|
||||||
* Fixed some MCD support bugs
|
|
||||||
* Default output format for Kindle DX is now CBZ
|
|
||||||
|
|
||||||
####4.2:
|
|
||||||
* Added [Manga Cover Database](http://manga.joentjuh.nl/) support
|
|
||||||
* Officially dropped Windows XP support
|
|
||||||
* Fixed _Other_ profile
|
|
||||||
* Fixed problems with page order on stock KOBO CBZ reader
|
|
||||||
* Many other small bug fixes and tweaks
|
|
||||||
|
|
||||||
####4.1:
|
|
||||||
* Thanks to code contributed by Kevin Hendricks speed of MOBI creation was greatly increased
|
|
||||||
* Improved performance on Windows
|
|
||||||
* Improved MOBI splitting and changed maximal size of output file
|
|
||||||
* Fixed _No optimization_ mode
|
|
||||||
* Multiple small tweaks nad minor bug fixes
|
|
||||||
|
|
||||||
####4.0.2:
|
|
||||||
* Fixed some Windows and OSX specific bugs
|
|
||||||
* Fixed problem with marigns when using HQ mode
|
|
||||||
|
|
||||||
####4.0.1:
|
|
||||||
* Fixed file lock problems that plagued some Windows users
|
|
||||||
* Fixed content server failing to start on Windows
|
|
||||||
* Improved performance of WebToon splitter
|
|
||||||
* Tweaked margin color detection
|
|
||||||
|
|
||||||
####4.0:
|
|
||||||
* 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
|
|
||||||
|
|
||||||
####3.7.2:
|
|
||||||
* Fixed problems with HQ mode
|
|
||||||
|
|
||||||
####3.7.1:
|
|
||||||
* Hotfixed Kobo profiles
|
|
||||||
|
|
||||||
####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
|
|
||||||
|
|
||||||
####3.6.2:
|
|
||||||
* Fixed previous PNG output fix
|
|
||||||
* Fixed Panel View anomalies
|
|
||||||
|
|
||||||
####3.6.1:
|
|
||||||
* Fixed PNG output
|
|
||||||
|
|
||||||
####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.5:
|
|
||||||
* Added simple content server - Converted files can be now delivered wireless
|
|
||||||
* Added proper Windows installer
|
|
||||||
* Improved multiprocessing speed
|
|
||||||
* GUI tweaks and minor bug fixes
|
|
||||||
|
|
||||||
####3.4:
|
|
||||||
* 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
|
|
||||||
* Margin color fill is now autodetected
|
|
||||||
* Created MOBI files are not longer marked as _Personal_ on newer Kindle models
|
|
||||||
* Layout of panels in Panel View mode is now automatically adjusted to content
|
|
||||||
* Fixed Kindle 2/DX/DXG profiles - no more blank pages
|
|
||||||
* All Kindle Fire profiles now support hiqh quality Panel View
|
|
||||||
* Added support of 7z/CB7 files
|
|
||||||
* Added Kindle Fire HDX profile
|
|
||||||
* Support for Virtual Panel View was removed
|
|
||||||
* Profiles for Kindle Keyboard, Touch and Non-Touch are now merged
|
|
||||||
* Windows release is now bundled with UnRAR and 7za
|
|
||||||
* Small 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.2.1:
|
|
||||||
* Hotfixed crash occurring on OS with Russian locale
|
|
||||||
|
|
||||||
####3.1:
|
|
||||||
* Added profile: Kindle for Android
|
|
||||||
* Add file/directory dialogs now support multiselect
|
|
||||||
* Many small fixes and tweaks
|
|
||||||
|
|
||||||
####3.0:
|
|
||||||
* New QT GUI
|
|
||||||
* Merge with AWKCC
|
|
||||||
* Added ultra quality mode
|
|
||||||
* Added support for custom width/height
|
|
||||||
* Added option to disable color conversion
|
|
||||||
|
|
||||||
####2.10:
|
|
||||||
* 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)
|
|
||||||
|
|
||||||
####2.9
|
|
||||||
* Added support for generating a plain CBZ (skipping all the EPUB/MOBI generation) (#45)
|
|
||||||
* Prevent output file overwriting the source one: if a duplicate name is detected, append _kcc to the name
|
|
||||||
* Rarfile library updated to 2.6
|
|
||||||
* Added GIF, TIFF and BMP to supported formats (#42)
|
|
||||||
* Filenames slugifications (#28, #31, #9, #8)
|
|
||||||
|
|
||||||
####2.8
|
|
||||||
* 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)
|
|
||||||
|
|
||||||
####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
|
|
||||||
|
|
||||||
####2.6
|
|
||||||
* Added --rotate option to rotate landscape images instead of splitting them (#16, #24)
|
|
||||||
* Added --output option to customize EPUB output dir/file (#22)
|
|
||||||
* Add rendition:layout and rendition:orientation EPUB meta tags (supported by new kindlegen 2.8)
|
|
||||||
* Fixed natural sorting for files (#18)
|
|
||||||
|
|
||||||
####2.5
|
|
||||||
* Added --black-borders option to set added borders black when page's ratio is not the device's one (#11).
|
|
||||||
* Fixes EPUB containing zipped itself (#10)
|
|
||||||
|
|
||||||
####2.4
|
|
||||||
* Use temporary directory as workdir (fixes converting from external volumes and zipfiles renaming)
|
|
||||||
* Fixed "add folders" from GUI.
|
|
||||||
|
|
||||||
####2.3
|
|
||||||
* Fixed win32 EPUB generation, folder handling, filenames with spaces and subfolders
|
|
||||||
|
|
||||||
####2.2:
|
|
||||||
* Added (valid!) EPUB 2.0 output
|
|
||||||
* Rename .zip files to .cbz to avoid overwriting
|
|
||||||
|
|
||||||
####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
|
|
||||||
|
|
||||||
## PRIVACY
|
## PRIVACY
|
||||||
**KCC** is initiating internet connections in three cases:
|
**KCC** is initiating internet connections in three cases:
|
||||||
* During startup - Version check
|
* During startup - Version check
|
||||||
@@ -502,5 +181,5 @@ The app relies and includes the following scripts:
|
|||||||
Please check [wiki page](https://github.com/ciromattia/kcc/wiki/Known-issues).
|
Please check [wiki page](https://github.com/ciromattia/kcc/wiki/Known-issues).
|
||||||
|
|
||||||
## COPYRIGHT
|
## COPYRIGHT
|
||||||
Copyright (c) 2012-2017 Ciro Mattia Gonano and Paweł Jastrzębski.
|
Copyright (c) 2012-2018 Ciro Mattia Gonano and Paweł Jastrzębski.
|
||||||
**KCC** is released under ISC LICENSE; see LICENSE.txt for further details.
|
**KCC** is released under ISC LICENSE; see LICENSE.txt for further details.
|
||||||
|
|||||||
25
appveyor.yml
Normal file
25
appveyor.yml
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
environment:
|
||||||
|
PYTHON: "C:\\Python36-x64"
|
||||||
|
|
||||||
|
install:
|
||||||
|
- set PATH="%PYTHON%\\Scripts";"C:\\Program Files (x86)\\Inno Setup 5";%PATH%
|
||||||
|
- "%PYTHON%\\python.exe -m pip install --upgrade pip setuptools wheel"
|
||||||
|
- "%PYTHON%\\python.exe -m pip install -r requirements.txt"
|
||||||
|
- "%PYTHON%\\python.exe -m pip install certifi PyInstaller"
|
||||||
|
- nuget install secure-file -ExcludeVersion
|
||||||
|
- secure-file\tools\secure-file -decrypt other\windows\sentry.py.enc -out kindlecomicconverter\sentry.py -secret %ENCRYPTION%
|
||||||
|
|
||||||
|
build_script:
|
||||||
|
- "%PYTHON%\\python.exe setup.py build_binary"
|
||||||
|
|
||||||
|
after_build:
|
||||||
|
- ps: Get-ChildItem .\dist\KCC* | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name }
|
||||||
|
|
||||||
|
deploy:
|
||||||
|
provider: S3
|
||||||
|
access_key_id:
|
||||||
|
secure: pWfyU8wtAHt354mBILwM41TemOjb+My9n3CRMnrpLzI=
|
||||||
|
secret_access_key:
|
||||||
|
secure: G0Xpxe355LMqV3s8v+TsdJYdmhFoKKA+mxK37Tlu8yNwKXKJgcnY7pcFKSdX5xS5
|
||||||
|
bucket: kcc-deploy
|
||||||
|
region: eu-central-1
|
||||||
18
docker/Build
18
docker/Build
@@ -1,18 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
set -e
|
|
||||||
|
|
||||||
pip3 install --upgrade pip setuptools wheel
|
|
||||||
pip3 install pillow python-slugify psutil pyinstaller raven pyqt5 certifi
|
|
||||||
gem install fpm
|
|
||||||
|
|
||||||
cd /app
|
|
||||||
pyinstaller -F -s kcc.py
|
|
||||||
mkdir -p dist/usr/bin dist/usr/share/applications dist/usr/share/doc/kindlecomicconverter dist/usr/share/kindlecomicconverter dist/usr/share/lintian/overrides
|
|
||||||
mv dist/kcc dist/usr/bin
|
|
||||||
cp icons/comic2ebook.png dist/usr/share/kindlecomicconverter
|
|
||||||
cp LICENSE.txt dist/usr/share/doc/kindlecomicconverter/copyright
|
|
||||||
cp other/linux/kindlecomicconverter.desktop dist/usr/share/applications
|
|
||||||
cp other/linux/kindlecomicconverter dist/usr/share/lintian/overrides
|
|
||||||
|
|
||||||
cd /app/dist
|
|
||||||
fpm -f -s dir -t deb -n kindlecomicconverter -v $KCCVER -m "Paweł Jastrzębski <pawelj@iosphe.re>" --license "ISC" --description "$(printf "Comic and Manga converter for e-book readers.\nThis app allows you to transform your PNG, JPG, GIF, CBZ, CBR and CB7 files\ninto EPUB or MOBI format e-books.")" --url "https://kcc.iosphe.re/" --deb-priority "optional" --vendor "" --category "graphics" -d "unrar | unrar-free" -d "p7zip-full" -d "libc6" usr
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
# acidweb/kcc
|
|
||||||
FROM debian:jessie
|
|
||||||
MAINTAINER Paweł Jastrzębski <pawelj@iosphe.re>
|
|
||||||
|
|
||||||
ADD ./Build /Build
|
|
||||||
|
|
||||||
RUN printf "deb http://httpredir.debian.org/debian stretch main" > /etc/apt/sources.list.d/stretch.list
|
|
||||||
RUN printf "Package: *\nPin: release a=testing\nPin-Priority: 400\n" > /etc/apt/preferences.d/stretch.pref
|
|
||||||
RUN apt-get update && apt-get -y dist-upgrade
|
|
||||||
RUN apt-get -y install build-essential curl ruby ruby-dev libpng-dev libjpeg-dev
|
|
||||||
RUN apt-get -y -t testing install python3 python3-dev python3-pyqt5
|
|
||||||
RUN curl https://bootstrap.pypa.io/get-pip.py | python3
|
|
||||||
RUN apt-get clean -y && apt-get autoclean -y && apt-get autoremove -y && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
|
||||||
|
|
||||||
CMD /Build
|
|
||||||
79
gui/KCC.ui
79
gui/KCC.ui
@@ -66,7 +66,16 @@
|
|||||||
<bool>false</bool>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout_3">
|
<layout class="QGridLayout" name="gridLayout_3">
|
||||||
<property name="margin">
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
<number>0</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
<item row="0" column="2">
|
<item row="0" column="2">
|
||||||
@@ -78,7 +87,7 @@
|
|||||||
</sizepolicy>
|
</sizepolicy>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string><html><head/><body><p style='white-space:pre'>Resolution of target device.</p></body></html></string>
|
<string><html><head/><body><p style='white-space:pre'>Resolution of the target device.</p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Custom height:</string>
|
<string>Custom height:</string>
|
||||||
@@ -88,7 +97,7 @@
|
|||||||
<item row="0" column="1">
|
<item row="0" column="1">
|
||||||
<widget class="QSpinBox" name="widthBox">
|
<widget class="QSpinBox" name="widthBox">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string><html><head/><body><p style='white-space:pre'>Resolution of target device.</p></body></html></string>
|
<string><html><head/><body><p style='white-space:pre'>Resolution of the target device.</p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="maximum">
|
<property name="maximum">
|
||||||
<number>2160</number>
|
<number>2160</number>
|
||||||
@@ -104,7 +113,7 @@
|
|||||||
</sizepolicy>
|
</sizepolicy>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string><html><head/><body><p style='white-space:pre'>Resolution of target device.</p></body></html></string>
|
<string><html><head/><body><p style='white-space:pre'>Resolution of the target device.</p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Custom width:</string>
|
<string>Custom width:</string>
|
||||||
@@ -114,7 +123,7 @@
|
|||||||
<item row="0" column="3">
|
<item row="0" column="3">
|
||||||
<widget class="QSpinBox" name="heightBox">
|
<widget class="QSpinBox" name="heightBox">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string><html><head/><body><p style='white-space:pre'>Resolution of target device.</p></body></html></string>
|
<string><html><head/><body><p style='white-space:pre'>Resolution of the target device.</p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="maximum">
|
<property name="maximum">
|
||||||
<number>3840</number>
|
<number>3840</number>
|
||||||
@@ -127,7 +136,16 @@
|
|||||||
<item row="4" column="0" colspan="2">
|
<item row="4" column="0" colspan="2">
|
||||||
<widget class="QWidget" name="optionWidget" native="true">
|
<widget class="QWidget" name="optionWidget" native="true">
|
||||||
<layout class="QGridLayout" name="gridLayout_2">
|
<layout class="QGridLayout" name="gridLayout_2">
|
||||||
<property name="margin">
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
<number>0</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
<item row="0" column="0">
|
<item row="0" column="0">
|
||||||
@@ -156,10 +174,13 @@
|
|||||||
<item row="0" column="2">
|
<item row="0" column="2">
|
||||||
<widget class="QCheckBox" name="qualityBox">
|
<widget class="QCheckBox" name="qualityBox">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string><html><head/><body><p style=\'white-space:pre\'><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - 4 panels<br/></span>Zoom each corner separately.</p><p style=\'white-space:pre\'><span style=\" font-weight:600; text-decoration: underline;\">Checked - 2 panels<br/></span>Zoom only the top and bottom of the page.</p></body></html></string>
|
<string><html><head/><body><p style='white-space:pre'><span style=" font-weight:600; text-decoration: underline;">Unchecked - 4 panels<br/></span>Zoom each corner separately.</p><p style='white-space:pre'><span style=" font-weight:600; text-decoration: underline;">Indeterminate - 2 panels<br/></span>Zoom only the top and bottom of the page.</p><p><span style=" font-weight:600; text-decoration: underline;">Checked - 4 high-quality panels<br/></span>Zoom each corner separately. Try to increase the quality of magnification. Check wiki for more details.</p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Panel View 4/2</string>
|
<string>Panel View 4/2/HQ</string>
|
||||||
|
</property>
|
||||||
|
<property name="tristate">
|
||||||
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@@ -199,7 +220,7 @@
|
|||||||
<item row="2" column="0">
|
<item row="2" column="0">
|
||||||
<widget class="QCheckBox" name="borderBox">
|
<widget class="QCheckBox" name="borderBox">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string><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></string>
|
<string><html><head/><body><p><span style=" font-weight:600; text-decoration: underline;">Unchecked - Autodetection<br/></span>The 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></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>W/B margins</string>
|
<string>W/B margins</string>
|
||||||
@@ -212,7 +233,7 @@
|
|||||||
<item row="2" column="1">
|
<item row="2" column="1">
|
||||||
<widget class="QCheckBox" name="outputSplit">
|
<widget class="QCheckBox" name="outputSplit">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string><html><head/><body><p style='white-space:pre'><span style=" font-weight:600; text-decoration: underline;">Unchecked - Automatic mode<br/></span>Output will be splitted automatically.</p><p style='white-space:pre'><span style=" font-weight:600; text-decoration: underline;">Checked - Volume mode<br/></span>Every subdirectory will be considered as separate volume.</p></body></html></string>
|
<string><html><head/><body><p style='white-space:pre'><span style=" font-weight:600; text-decoration: underline;">Unchecked - Automatic mode<br/></span>The output will be split automatically.</p><p style='white-space:pre'><span style=" font-weight:600; text-decoration: underline;">Checked - Volume mode<br/></span>Every subdirectory will be considered as a separate volume.</p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Output split</string>
|
<string>Output split</string>
|
||||||
@@ -238,7 +259,16 @@
|
|||||||
<bool>false</bool>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
<property name="margin">
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
<number>0</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
<item>
|
<item>
|
||||||
@@ -267,7 +297,16 @@
|
|||||||
<item row="0" column="0" colspan="2">
|
<item row="0" column="0" colspan="2">
|
||||||
<widget class="QWidget" name="toolWidget" native="true">
|
<widget class="QWidget" name="toolWidget" native="true">
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
<property name="margin">
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
<number>0</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
<item>
|
<item>
|
||||||
@@ -281,6 +320,9 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Editor</string>
|
<string>Editor</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><html><head/><body><p style='white-space:pre'>Shift+Click to edit directory.</p></body></html></string>
|
||||||
|
</property>
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
<iconset resource="KCC.qrc">
|
<iconset resource="KCC.qrc">
|
||||||
<normaloff>:/Other/icons/editor.png</normaloff>:/Other/icons/editor.png</iconset>
|
<normaloff>:/Other/icons/editor.png</normaloff>:/Other/icons/editor.png</iconset>
|
||||||
@@ -316,7 +358,16 @@
|
|||||||
</sizepolicy>
|
</sizepolicy>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout_4">
|
<layout class="QGridLayout" name="gridLayout_4">
|
||||||
<property name="margin">
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
<number>0</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
<item row="0" column="0">
|
<item row="0" column="0">
|
||||||
@@ -406,7 +457,7 @@
|
|||||||
</font>
|
</font>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string><html><head/><body><p style='white-space:pre'>Shift+Click to select the output directory.</p></body></html></string>
|
<string><html><head/><body><p style='white-space:pre'>Shift+Click to select the output directory.</p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Convert</string>
|
<string>Convert</string>
|
||||||
|
|||||||
11
kcc-c2e.py
11
kcc-c2e.py
@@ -2,7 +2,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
||||||
# Copyright (c) 2013-2017 Pawel Jastrzebski <pawelj@iosphe.re>
|
# Copyright (c) 2013-2018 Pawel Jastrzebski <pawelj@iosphe.re>
|
||||||
#
|
#
|
||||||
# Permission to use, copy, modify, and/or distribute this software for
|
# Permission to use, copy, modify, and/or distribute this software for
|
||||||
# any purpose with or without fee is hereby granted, provided that the
|
# any purpose with or without fee is hereby granted, provided that the
|
||||||
@@ -23,14 +23,9 @@ if sys.version_info[0] != 3:
|
|||||||
print('ERROR: This is Python 3 script!')
|
print('ERROR: This is Python 3 script!')
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
from kindlecomicconverter.shared import dependencyCheck
|
|
||||||
dependencyCheck(2)
|
|
||||||
|
|
||||||
from multiprocessing import freeze_support
|
from multiprocessing import freeze_support
|
||||||
from kindlecomicconverter import __version__
|
from kindlecomicconverter.startup import startC2E
|
||||||
from kindlecomicconverter.comic2ebook import main
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
freeze_support()
|
freeze_support()
|
||||||
print('comic2ebook v' + __version__ + ' - Written by Ciro Mattia Gonano and Pawel Jastrzebski.')
|
startC2E()
|
||||||
sys.exit(main(sys.argv[1:]))
|
|
||||||
|
|||||||
11
kcc-c2p.py
11
kcc-c2p.py
@@ -2,7 +2,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
||||||
# Copyright (c) 2013-2017 Pawel Jastrzebski <pawelj@iosphe.re>
|
# Copyright (c) 2013-2018 Pawel Jastrzebski <pawelj@iosphe.re>
|
||||||
#
|
#
|
||||||
# Permission to use, copy, modify, and/or distribute this software for
|
# Permission to use, copy, modify, and/or distribute this software for
|
||||||
# any purpose with or without fee is hereby granted, provided that the
|
# any purpose with or without fee is hereby granted, provided that the
|
||||||
@@ -23,14 +23,9 @@ if sys.version_info[0] != 3:
|
|||||||
print('ERROR: This is Python 3 script!')
|
print('ERROR: This is Python 3 script!')
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
from kindlecomicconverter.shared import dependencyCheck
|
|
||||||
dependencyCheck(1)
|
|
||||||
|
|
||||||
from multiprocessing import freeze_support
|
from multiprocessing import freeze_support
|
||||||
from kindlecomicconverter import __version__
|
from kindlecomicconverter.startup import startC2P
|
||||||
from kindlecomicconverter.comic2panel import main
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
freeze_support()
|
freeze_support()
|
||||||
print('comic2panel v' + __version__ + ' - Written by Ciro Mattia Gonano and Pawel Jastrzebski.')
|
startC2P()
|
||||||
sys.exit(main(sys.argv[1:]))
|
|
||||||
|
|||||||
6
kcc.iss
6
kcc.iss
@@ -1,5 +1,5 @@
|
|||||||
#define MyAppName "Kindle Comic Converter"
|
#define MyAppName "Kindle Comic Converter"
|
||||||
#define MyAppVersion "5.3.0"
|
#define MyAppVersion "5.4.4"
|
||||||
#define MyAppPublisher "Ciro Mattia Gonano, Paweł Jastrzębski"
|
#define MyAppPublisher "Ciro Mattia Gonano, Paweł Jastrzębski"
|
||||||
#define MyAppURL "http://kcc.iosphe.re/"
|
#define MyAppURL "http://kcc.iosphe.re/"
|
||||||
#define MyAppExeName "KCC.exe"
|
#define MyAppExeName "KCC.exe"
|
||||||
@@ -12,7 +12,7 @@ AppPublisher={#MyAppPublisher}
|
|||||||
AppPublisherURL={#MyAppURL}
|
AppPublisherURL={#MyAppURL}
|
||||||
AppSupportURL={#MyAppURL}
|
AppSupportURL={#MyAppURL}
|
||||||
AppUpdatesURL={#MyAppURL}
|
AppUpdatesURL={#MyAppURL}
|
||||||
AppCopyright=Copyright (C) 2012-2017 Ciro Mattia Gonano and Paweł Jastrzębski
|
AppCopyright=Copyright (C) 2012-2018 Ciro Mattia Gonano and Paweł Jastrzębski
|
||||||
ArchitecturesAllowed=x64
|
ArchitecturesAllowed=x64
|
||||||
DefaultDirName={pf}\{#MyAppName}
|
DefaultDirName={pf}\{#MyAppName}
|
||||||
DefaultGroupName={#MyAppName}
|
DefaultGroupName={#MyAppName}
|
||||||
@@ -49,7 +49,6 @@ Source: "LICENSE.txt"; DestDir: "{app}"; Flags: ignoreversion solidbreak
|
|||||||
Source: "other\windows\Additional-LICENSE.txt"; DestDir: "{app}"; Flags: ignoreversion
|
Source: "other\windows\Additional-LICENSE.txt"; DestDir: "{app}"; Flags: ignoreversion
|
||||||
Source: "other\windows\UnRAR.exe"; DestDir: "{app}"; Flags: ignoreversion
|
Source: "other\windows\UnRAR.exe"; DestDir: "{app}"; Flags: ignoreversion
|
||||||
Source: "other\windows\7za.exe"; DestDir: "{app}"; Flags: ignoreversion
|
Source: "other\windows\7za.exe"; DestDir: "{app}"; Flags: ignoreversion
|
||||||
Source: "other\windows\vc_redist.x64.exe"; DestDir: "{tmp}"; Flags: ignoreversion deleteafterinstall
|
|
||||||
|
|
||||||
[Icons]
|
[Icons]
|
||||||
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
|
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
|
||||||
@@ -57,7 +56,6 @@ Name: "{group}\Readme"; Filename: "https://github.com/ciromattia/kcc#kcc"
|
|||||||
Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
|
Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
|
||||||
|
|
||||||
[Run]
|
[Run]
|
||||||
Filename: "{tmp}\vc_redist.x64.exe"; Parameters: "/install /passive /norestart"; StatusMsg: "Installing Microsoft Visual C++ 2015 Redistributable Package..."
|
|
||||||
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall
|
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall
|
||||||
|
|
||||||
[Messages]
|
[Messages]
|
||||||
|
|||||||
41
kcc.py
41
kcc.py
@@ -2,7 +2,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
||||||
# Copyright (c) 2013-2017 Pawel Jastrzebski <pawelj@iosphe.re>
|
# Copyright (c) 2013-2018 Pawel Jastrzebski <pawelj@iosphe.re>
|
||||||
#
|
#
|
||||||
# Permission to use, copy, modify, and/or distribute this software for
|
# Permission to use, copy, modify, and/or distribute this software for
|
||||||
# any purpose with or without fee is hereby granted, provided that the
|
# any purpose with or without fee is hereby granted, provided that the
|
||||||
@@ -34,23 +34,6 @@ if sys.platform.startswith('darwin'):
|
|||||||
else:
|
else:
|
||||||
os.environ['PATH'] = os.path.dirname(os.path.abspath(__file__)) + '/other/osx/:' + os.environ['PATH']
|
os.environ['PATH'] = os.path.dirname(os.path.abspath(__file__)) + '/other/osx/:' + os.environ['PATH']
|
||||||
elif sys.platform.startswith('win'):
|
elif sys.platform.startswith('win'):
|
||||||
import multiprocessing.popen_spawn_win32 as forking
|
|
||||||
|
|
||||||
class _Popen(forking.Popen):
|
|
||||||
def __init__(self, *args, **kw):
|
|
||||||
if hasattr(sys, 'frozen'):
|
|
||||||
# noinspection PyProtectedMember
|
|
||||||
os.putenv('_MEIPASS2', sys._MEIPASS)
|
|
||||||
try:
|
|
||||||
super(_Popen, self).__init__(*args, **kw)
|
|
||||||
finally:
|
|
||||||
if hasattr(sys, 'frozen'):
|
|
||||||
if hasattr(os, 'unsetenv'):
|
|
||||||
os.unsetenv('_MEIPASS2')
|
|
||||||
else:
|
|
||||||
os.putenv('_MEIPASS2', '')
|
|
||||||
forking.Popen = _Popen
|
|
||||||
|
|
||||||
if getattr(sys, 'frozen', False):
|
if getattr(sys, 'frozen', False):
|
||||||
os.chdir(os.path.dirname(os.path.abspath(sys.executable)))
|
os.chdir(os.path.dirname(os.path.abspath(sys.executable)))
|
||||||
else:
|
else:
|
||||||
@@ -60,27 +43,13 @@ elif sys.platform.startswith('win'):
|
|||||||
if getattr(sys, 'frozen', False):
|
if getattr(sys, 'frozen', False):
|
||||||
try:
|
try:
|
||||||
import kindlecomicconverter.sentry
|
import kindlecomicconverter.sentry
|
||||||
except:
|
except ImportError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
from kindlecomicconverter.shared import dependencyCheck
|
|
||||||
dependencyCheck(3)
|
|
||||||
|
|
||||||
from multiprocessing import freeze_support
|
from multiprocessing import freeze_support
|
||||||
from kindlecomicconverter import KCC_gui
|
from kindlecomicconverter.startup import start
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
freeze_support()
|
freeze_support()
|
||||||
os.environ['QT_AUTO_SCREEN_SCALE_FACTOR'] = "1"
|
start()
|
||||||
KCCAplication = KCC_gui.QApplicationMessaging(sys.argv)
|
|
||||||
if KCCAplication.isRunning():
|
|
||||||
if len(sys.argv) > 1:
|
|
||||||
KCCAplication.sendMessage(sys.argv[1])
|
|
||||||
else:
|
|
||||||
KCCAplication.sendMessage('ARISE')
|
|
||||||
else:
|
|
||||||
KCCWindow = KCC_gui.QMainWindowKCC()
|
|
||||||
KCCUI = KCC_gui.KCCGUI(KCCAplication, KCCWindow)
|
|
||||||
if len(sys.argv) > 1:
|
|
||||||
KCCUI.handleMessage(sys.argv[1])
|
|
||||||
sys.exit(KCCAplication.exec_())
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
||||||
# Copyright (c) 2013-2017 Pawel Jastrzebski <pawelj@iosphe.re>
|
# Copyright (c) 2013-2018 Pawel Jastrzebski <pawelj@iosphe.re>
|
||||||
#
|
#
|
||||||
# Permission to use, copy, modify, and/or distribute this software for
|
# Permission to use, copy, modify, and/or distribute this software for
|
||||||
# any purpose with or without fee is hereby granted, provided that the
|
# any purpose with or without fee is hereby granted, provided that the
|
||||||
@@ -26,12 +26,12 @@ from shutil import move
|
|||||||
from subprocess import STDOUT, PIPE
|
from subprocess import STDOUT, PIPE
|
||||||
from PyQt5 import QtGui, QtCore, QtWidgets, QtNetwork
|
from PyQt5 import QtGui, QtCore, QtWidgets, QtNetwork
|
||||||
from xml.dom.minidom import parse
|
from xml.dom.minidom import parse
|
||||||
|
from xml.sax.saxutils import escape
|
||||||
from psutil import Popen, Process
|
from psutil import Popen, Process
|
||||||
from copy import copy
|
from copy import copy
|
||||||
from distutils.version import StrictVersion
|
from distutils.version import StrictVersion
|
||||||
from xml.sax.saxutils import escape
|
|
||||||
from raven import Client
|
from raven import Client
|
||||||
from .shared import md5Checksum, HTMLStripper, sanitizeTrace, saferRemove
|
from .shared import md5Checksum, HTMLStripper, sanitizeTrace
|
||||||
from . import __version__
|
from . import __version__
|
||||||
from . import comic2ebook
|
from . import comic2ebook
|
||||||
from . import metadata
|
from . import metadata
|
||||||
@@ -152,12 +152,12 @@ class VersionThread(QtCore.QThread):
|
|||||||
self.getNewVersion()
|
self.getNewVersion()
|
||||||
else:
|
else:
|
||||||
MW.addMessage.emit('<a href="https://kcc.iosphe.re/">'
|
MW.addMessage.emit('<a href="https://kcc.iosphe.re/">'
|
||||||
'<b>New version is available!</b></a> '
|
'<b>The new version is available!</b></a> '
|
||||||
'(<a href="https://github.com/ciromattia/kcc/releases/">'
|
'(<a href="https://github.com/ciromattia/kcc/releases/">'
|
||||||
'Changelog</a>)', 'warning', False)
|
'Changelog</a>)', 'warning', False)
|
||||||
|
|
||||||
def setAnswer(self, dialogAnswer):
|
def setAnswer(self, dialoganswer):
|
||||||
self.answer = dialogAnswer
|
self.answer = dialoganswer
|
||||||
|
|
||||||
def getNewVersion(self):
|
def getNewVersion(self):
|
||||||
while self.answer is None:
|
while self.answer is None:
|
||||||
@@ -176,12 +176,12 @@ class VersionThread(QtCore.QThread):
|
|||||||
Popen(path[0] + '.exe /SP- /silent /noicons', stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=True)
|
Popen(path[0] + '.exe /SP- /silent /noicons', stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=True)
|
||||||
MW.forceShutdown.emit()
|
MW.forceShutdown.emit()
|
||||||
except Exception:
|
except Exception:
|
||||||
MW.addMessage.emit('Failed to download update!', 'warning', False)
|
MW.addMessage.emit('Failed to download the update!', 'warning', False)
|
||||||
MW.hideProgressBar.emit()
|
MW.hideProgressBar.emit()
|
||||||
MW.modeConvert.emit(1)
|
MW.modeConvert.emit(1)
|
||||||
|
|
||||||
def getNewVersionTick(self, size, blockSize, totalSize):
|
def getNewVersionTick(self, size, blocksize, totalsize):
|
||||||
progress = int((size / (totalSize // blockSize)) * 100)
|
progress = int((size / (totalsize // blocksize)) * 100)
|
||||||
if size == 0:
|
if size == 0:
|
||||||
MW.progressBarTick.emit('100')
|
MW.progressBarTick.emit('100')
|
||||||
if progress > self.barProgress:
|
if progress > self.barProgress:
|
||||||
@@ -254,8 +254,10 @@ class WorkerThread(QtCore.QThread):
|
|||||||
options.splitter = 2
|
options.splitter = 2
|
||||||
elif GUI.rotateBox.checkState() == 2:
|
elif GUI.rotateBox.checkState() == 2:
|
||||||
options.splitter = 1
|
options.splitter = 1
|
||||||
if GUI.qualityBox.isChecked():
|
if GUI.qualityBox.checkState() == 1:
|
||||||
options.autoscale = True
|
options.autoscale = True
|
||||||
|
elif GUI.qualityBox.checkState() == 2:
|
||||||
|
options.hq = True
|
||||||
if GUI.webtoonBox.isChecked():
|
if GUI.webtoonBox.isChecked():
|
||||||
options.webtoon = True
|
options.webtoon = True
|
||||||
if GUI.upscaleBox.checkState() == 1:
|
if GUI.upscaleBox.checkState() == 1:
|
||||||
@@ -334,7 +336,7 @@ class WorkerThread(QtCore.QThread):
|
|||||||
if 'outputPath' in locals():
|
if 'outputPath' in locals():
|
||||||
for item in outputPath:
|
for item in outputPath:
|
||||||
if os.path.exists(item):
|
if os.path.exists(item):
|
||||||
saferRemove(item)
|
os.remove(item)
|
||||||
self.clean()
|
self.clean()
|
||||||
return
|
return
|
||||||
if not self.errors:
|
if not self.errors:
|
||||||
@@ -361,9 +363,9 @@ class WorkerThread(QtCore.QThread):
|
|||||||
if not self.conversionAlive:
|
if not self.conversionAlive:
|
||||||
for item in outputPath:
|
for item in outputPath:
|
||||||
if os.path.exists(item):
|
if os.path.exists(item):
|
||||||
saferRemove(item)
|
os.remove(item)
|
||||||
if os.path.exists(item.replace('.epub', '.mobi')):
|
if os.path.exists(item.replace('.epub', '.mobi')):
|
||||||
saferRemove(item.replace('.epub', '.mobi'))
|
os.remove(item.replace('.epub', '.mobi'))
|
||||||
self.clean()
|
self.clean()
|
||||||
return
|
return
|
||||||
if self.kindlegenErrorCode[0] == 0:
|
if self.kindlegenErrorCode[0] == 0:
|
||||||
@@ -384,7 +386,7 @@ class WorkerThread(QtCore.QThread):
|
|||||||
for item in outputPath:
|
for item in outputPath:
|
||||||
GUI.progress.content = ''
|
GUI.progress.content = ''
|
||||||
mobiPath = item.replace('.epub', '.mobi')
|
mobiPath = item.replace('.epub', '.mobi')
|
||||||
saferRemove(mobiPath + '_toclean')
|
os.remove(mobiPath + '_toclean')
|
||||||
if GUI.targetDirectory and GUI.targetDirectory != os.path.dirname(mobiPath):
|
if GUI.targetDirectory and GUI.targetDirectory != os.path.dirname(mobiPath):
|
||||||
try:
|
try:
|
||||||
move(mobiPath, GUI.targetDirectory)
|
move(mobiPath, GUI.targetDirectory)
|
||||||
@@ -402,9 +404,9 @@ class WorkerThread(QtCore.QThread):
|
|||||||
for item in outputPath:
|
for item in outputPath:
|
||||||
mobiPath = item.replace('.epub', '.mobi')
|
mobiPath = item.replace('.epub', '.mobi')
|
||||||
if os.path.exists(mobiPath):
|
if os.path.exists(mobiPath):
|
||||||
saferRemove(mobiPath)
|
os.remove(mobiPath)
|
||||||
if os.path.exists(mobiPath + '_toclean'):
|
if os.path.exists(mobiPath + '_toclean'):
|
||||||
saferRemove(mobiPath + '_toclean')
|
os.remove(mobiPath + '_toclean')
|
||||||
MW.addMessage.emit('Failed to process MOBI file!', 'error', False)
|
MW.addMessage.emit('Failed to process MOBI file!', 'error', False)
|
||||||
MW.addTrayMessage.emit('Failed to process MOBI file!', 'Critical')
|
MW.addTrayMessage.emit('Failed to process MOBI file!', 'Critical')
|
||||||
else:
|
else:
|
||||||
@@ -412,9 +414,9 @@ class WorkerThread(QtCore.QThread):
|
|||||||
epubSize = (os.path.getsize(self.kindlegenErrorCode[2])) // 1024 // 1024
|
epubSize = (os.path.getsize(self.kindlegenErrorCode[2])) // 1024 // 1024
|
||||||
for item in outputPath:
|
for item in outputPath:
|
||||||
if os.path.exists(item):
|
if os.path.exists(item):
|
||||||
saferRemove(item)
|
os.remove(item)
|
||||||
if os.path.exists(item.replace('.epub', '.mobi')):
|
if os.path.exists(item.replace('.epub', '.mobi')):
|
||||||
saferRemove(item.replace('.epub', '.mobi'))
|
os.remove(item.replace('.epub', '.mobi'))
|
||||||
MW.addMessage.emit('KindleGen failed to create MOBI!', 'error', False)
|
MW.addMessage.emit('KindleGen failed to create MOBI!', 'error', False)
|
||||||
MW.addTrayMessage.emit('KindleGen failed to create MOBI!', 'Critical')
|
MW.addTrayMessage.emit('KindleGen failed to create MOBI!', 'Critical')
|
||||||
if self.kindlegenErrorCode[0] == 1 and self.kindlegenErrorCode[1] != '':
|
if self.kindlegenErrorCode[0] == 1 and self.kindlegenErrorCode[1] != '':
|
||||||
@@ -498,28 +500,38 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
GUI.jobList.scrollToBottom()
|
GUI.jobList.scrollToBottom()
|
||||||
|
|
||||||
def selectFileMetaEditor(self):
|
def selectFileMetaEditor(self):
|
||||||
if self.UnRAR:
|
sname = ''
|
||||||
if self.sevenza:
|
if QtWidgets.QApplication.keyboardModifiers() == QtCore.Qt.ShiftModifier:
|
||||||
fname = QtWidgets.QFileDialog.getOpenFileName(MW, 'Select file', self.lastPath,
|
dname = QtWidgets.QFileDialog.getExistingDirectory(MW, 'Select directory', self.lastPath)
|
||||||
'Comic (*.cbz *.cbr *.cb7)')
|
if dname != '':
|
||||||
else:
|
sname = os.path.join(dname, 'ComicInfo.xml')
|
||||||
fname = QtWidgets.QFileDialog.getOpenFileName(MW, 'Select file', self.lastPath,
|
if sys.platform.startswith('win'):
|
||||||
'Comic (*.cbz *.cbr)')
|
sname = sname.replace('/', '\\')
|
||||||
|
self.lastPath = os.path.abspath(sname)
|
||||||
else:
|
else:
|
||||||
if self.sevenza:
|
if self.UnRAR:
|
||||||
fname = QtWidgets.QFileDialog.getOpenFileName(MW, 'Select file', self.lastPath,
|
if self.sevenza:
|
||||||
'Comic (*.cbz *.cb7)')
|
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:
|
else:
|
||||||
fname = QtWidgets.QFileDialog.getOpenFileName(MW, 'Select file', self.lastPath,
|
if self.sevenza:
|
||||||
'Comic (*.cbz)')
|
fname = QtWidgets.QFileDialog.getOpenFileName(MW, 'Select file', self.lastPath,
|
||||||
if fname[0] != '':
|
'Comic (*.cbz *.cb7)')
|
||||||
if sys.platform.startswith('win'):
|
else:
|
||||||
fname = fname[0].replace('/', '\\')
|
fname = QtWidgets.QFileDialog.getOpenFileName(MW, 'Select file', self.lastPath,
|
||||||
else:
|
'Comic (*.cbz)')
|
||||||
fname = fname[0]
|
if fname[0] != '':
|
||||||
self.lastPath = os.path.abspath(os.path.join(fname, os.pardir))
|
if sys.platform.startswith('win'):
|
||||||
|
sname = fname[0].replace('/', '\\')
|
||||||
|
else:
|
||||||
|
sname = fname[0]
|
||||||
|
self.lastPath = os.path.abspath(os.path.join(sname, os.pardir))
|
||||||
|
if sname != '':
|
||||||
try:
|
try:
|
||||||
self.editor.loadData(fname)
|
self.editor.loadData(sname)
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
_, _, traceback = sys.exc_info()
|
_, _, traceback = sys.exc_info()
|
||||||
GUI.sentry.captureException()
|
GUI.sentry.captureException()
|
||||||
@@ -531,8 +543,8 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
def clearJobs(self):
|
def clearJobs(self):
|
||||||
GUI.jobList.clear()
|
GUI.jobList.clear()
|
||||||
|
|
||||||
# noinspection PyCallByClass,PyTypeChecker
|
|
||||||
def openWiki(self):
|
def openWiki(self):
|
||||||
|
# noinspection PyCallByClass
|
||||||
QtGui.QDesktopServices.openUrl(QtCore.QUrl('https://github.com/ciromattia/kcc/wiki'))
|
QtGui.QDesktopServices.openUrl(QtCore.QUrl('https://github.com/ciromattia/kcc/wiki'))
|
||||||
|
|
||||||
def modeChange(self, mode):
|
def modeChange(self, mode):
|
||||||
@@ -613,6 +625,18 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
GUI.rotateBox.setEnabled(True)
|
GUI.rotateBox.setEnabled(True)
|
||||||
GUI.upscaleBox.setEnabled(True)
|
GUI.upscaleBox.setEnabled(True)
|
||||||
|
|
||||||
|
def togglequalityBox(self, value):
|
||||||
|
profile = GUI.profiles[str(GUI.deviceBox.currentText())]
|
||||||
|
if value == 2:
|
||||||
|
if profile['Label'] in ['KV', 'KO']:
|
||||||
|
self.addMessage('This option is intended for older Kindle models.', 'warning')
|
||||||
|
self.addMessage('On this device, quality improvement will be negligible.', 'warning')
|
||||||
|
GUI.upscaleBox.setEnabled(False)
|
||||||
|
GUI.upscaleBox.setChecked(True)
|
||||||
|
else:
|
||||||
|
GUI.upscaleBox.setEnabled(True)
|
||||||
|
GUI.upscaleBox.setChecked(profile['DefaultUpscale'])
|
||||||
|
|
||||||
def changeGamma(self, value):
|
def changeGamma(self, value):
|
||||||
valueRaw = int(5 * round(float(value) / 5))
|
valueRaw = int(5 * round(float(value) / 5))
|
||||||
value = '%.2f' % (float(valueRaw) / 100)
|
value = '%.2f' % (float(valueRaw) / 100)
|
||||||
@@ -634,7 +658,8 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
self.changeFormat()
|
self.changeFormat()
|
||||||
GUI.gammaSlider.setValue(0)
|
GUI.gammaSlider.setValue(0)
|
||||||
self.changeGamma(0)
|
self.changeGamma(0)
|
||||||
GUI.qualityBox.setEnabled(profile['PVOptions'])
|
if not GUI.webtoonBox.isChecked():
|
||||||
|
GUI.qualityBox.setEnabled(profile['PVOptions'])
|
||||||
GUI.upscaleBox.setChecked(profile['DefaultUpscale'])
|
GUI.upscaleBox.setChecked(profile['DefaultUpscale'])
|
||||||
if not profile['PVOptions']:
|
if not profile['PVOptions']:
|
||||||
GUI.qualityBox.setChecked(False)
|
GUI.qualityBox.setChecked(False)
|
||||||
@@ -642,13 +667,14 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
self.addMessage('<a href="https://github.com/ciromattia/kcc/wiki/NonKindle-devices">'
|
self.addMessage('<a href="https://github.com/ciromattia/kcc/wiki/NonKindle-devices">'
|
||||||
'List of supported Non-Kindle devices.</a>', 'info')
|
'List of supported Non-Kindle devices.</a>', 'info')
|
||||||
|
|
||||||
def changeFormat(self, outputFormat=None):
|
def changeFormat(self, outputformat=None):
|
||||||
profile = GUI.profiles[str(GUI.deviceBox.currentText())]
|
profile = GUI.profiles[str(GUI.deviceBox.currentText())]
|
||||||
if outputFormat is not None:
|
if outputformat is not None:
|
||||||
GUI.formatBox.setCurrentIndex(outputFormat)
|
GUI.formatBox.setCurrentIndex(outputformat)
|
||||||
else:
|
else:
|
||||||
GUI.formatBox.setCurrentIndex(profile['DefaultFormat'])
|
GUI.formatBox.setCurrentIndex(profile['DefaultFormat'])
|
||||||
GUI.qualityBox.setEnabled(profile['PVOptions'])
|
if not GUI.webtoonBox.isChecked():
|
||||||
|
GUI.qualityBox.setEnabled(profile['PVOptions'])
|
||||||
if str(GUI.formatBox.currentText()) == 'MOBI/AZW3':
|
if str(GUI.formatBox.currentText()) == 'MOBI/AZW3':
|
||||||
GUI.outputSplit.setEnabled(True)
|
GUI.outputSplit.setEnabled(True)
|
||||||
else:
|
else:
|
||||||
@@ -704,7 +730,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
def convertStart(self):
|
def convertStart(self):
|
||||||
if self.conversionAlive:
|
if self.conversionAlive:
|
||||||
GUI.convertButton.setEnabled(False)
|
GUI.convertButton.setEnabled(False)
|
||||||
self.addMessage('Process will be interrupted. Please wait.', 'warning')
|
self.addMessage('The process will be interrupted. Please wait.', 'warning')
|
||||||
self.conversionAlive = False
|
self.conversionAlive = False
|
||||||
self.worker.sync()
|
self.worker.sync()
|
||||||
else:
|
else:
|
||||||
@@ -750,7 +776,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
def saveSettings(self, event):
|
def saveSettings(self, event):
|
||||||
if self.conversionAlive:
|
if self.conversionAlive:
|
||||||
GUI.convertButton.setEnabled(False)
|
GUI.convertButton.setEnabled(False)
|
||||||
self.addMessage('Process will be interrupted. Please wait.', 'warning')
|
self.addMessage('The process will be interrupted. Please wait.', 'warning')
|
||||||
self.conversionAlive = False
|
self.conversionAlive = False
|
||||||
self.worker.sync()
|
self.worker.sync()
|
||||||
event.ignore()
|
event.ignore()
|
||||||
@@ -855,10 +881,10 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
else:
|
else:
|
||||||
self.addMessage('Download it and place executable in /usr/local/bin directory.', 'error')
|
self.addMessage('Download it and place executable in /usr/local/bin directory.', 'error')
|
||||||
|
|
||||||
def __init__(self, KCCAplication, KCCWindow):
|
def __init__(self, kccapp, kccwindow):
|
||||||
global APP, MW, GUI
|
global APP, MW, GUI
|
||||||
APP = KCCAplication
|
APP = kccapp
|
||||||
MW = KCCWindow
|
MW = kccwindow
|
||||||
GUI = self
|
GUI = self
|
||||||
self.setupUi(MW)
|
self.setupUi(MW)
|
||||||
self.editor = KCCGUI_MetaEditor()
|
self.editor = KCCGUI_MetaEditor()
|
||||||
@@ -902,6 +928,8 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
MW.resize(500, 500)
|
MW.resize(500, 500)
|
||||||
|
|
||||||
self.profiles = {
|
self.profiles = {
|
||||||
|
"Kindle Oasis 2": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
||||||
|
'DefaultUpscale': True, 'Label': 'KO'},
|
||||||
"Kindle Oasis": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
"Kindle Oasis": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
||||||
'DefaultUpscale': True, 'Label': 'KV'},
|
'DefaultUpscale': True, 'Label': 'KV'},
|
||||||
"Kindle Voyage": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
"Kindle Voyage": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
||||||
@@ -911,7 +939,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
"Kindle PW 1/2": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
"Kindle PW 1/2": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
||||||
'DefaultUpscale': False, 'Label': 'KPW'},
|
'DefaultUpscale': False, 'Label': 'KPW'},
|
||||||
"Kindle": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
"Kindle": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
||||||
'DefaultUpscale': False, 'Label': 'K45'},
|
'DefaultUpscale': False, 'Label': 'K578'},
|
||||||
"Kindle DX/DXG": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 2,
|
"Kindle DX/DXG": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 2,
|
||||||
'DefaultUpscale': False, 'Label': 'KDX'},
|
'DefaultUpscale': False, 'Label': 'KDX'},
|
||||||
"Kobo Mini/Touch": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1,
|
"Kobo Mini/Touch": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1,
|
||||||
@@ -934,10 +962,13 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
'DefaultUpscale': False, 'Label': 'K1'},
|
'DefaultUpscale': False, 'Label': 'K1'},
|
||||||
"Kindle 2": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 0,
|
"Kindle 2": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 0,
|
||||||
'DefaultUpscale': False, 'Label': 'K2'},
|
'DefaultUpscale': False, 'Label': 'K2'},
|
||||||
"Kindle 3": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
"Kindle Keyboard": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 0,
|
||||||
'DefaultUpscale': False, 'Label': 'K3'},
|
'DefaultUpscale': False, 'Label': 'K34'},
|
||||||
|
"Kindle Touch": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 0,
|
||||||
|
'DefaultUpscale': False, 'Label': 'K34'},
|
||||||
}
|
}
|
||||||
profilesGUI = [
|
profilesGUI = [
|
||||||
|
"Kindle Oasis 2",
|
||||||
"Kindle Oasis",
|
"Kindle Oasis",
|
||||||
"Kindle Voyage",
|
"Kindle Voyage",
|
||||||
"Kindle PW 3",
|
"Kindle PW 3",
|
||||||
@@ -948,16 +979,18 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
"Kobo Aura H2O",
|
"Kobo Aura H2O",
|
||||||
"Kobo Aura HD",
|
"Kobo Aura HD",
|
||||||
"Kobo Aura",
|
"Kobo Aura",
|
||||||
"Kobo Glo HD",
|
|
||||||
"Kobo Glo",
|
|
||||||
"Kobo Mini/Touch",
|
|
||||||
"Separator",
|
"Separator",
|
||||||
"Other",
|
"Other",
|
||||||
"Separator",
|
"Separator",
|
||||||
|
"Kindle Touch",
|
||||||
|
"Kindle Keyboard",
|
||||||
"Kindle DX/DXG",
|
"Kindle DX/DXG",
|
||||||
"Kindle 3",
|
|
||||||
"Kindle 2",
|
"Kindle 2",
|
||||||
"Kindle 1",
|
"Kindle 1",
|
||||||
|
"Separator",
|
||||||
|
"Kobo Glo HD",
|
||||||
|
"Kobo Glo",
|
||||||
|
"Kobo Mini/Touch",
|
||||||
]
|
]
|
||||||
|
|
||||||
statusBarLabel = QtWidgets.QLabel('<b><a href="https://kcc.iosphe.re/">HOMEPAGE</a> - <a href="https://github.'
|
statusBarLabel = QtWidgets.QLabel('<b><a href="https://kcc.iosphe.re/">HOMEPAGE</a> - <a href="https://github.'
|
||||||
@@ -969,9 +1002,9 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
GUI.statusBar.addPermanentWidget(statusBarLabel, 1)
|
GUI.statusBar.addPermanentWidget(statusBarLabel, 1)
|
||||||
|
|
||||||
self.addMessage('<b>Welcome!</b>', 'info')
|
self.addMessage('<b>Welcome!</b>', 'info')
|
||||||
self.addMessage('<b>Remember:</b> All options have additional informations in tooltips.', 'info')
|
self.addMessage('<b>Remember:</b> All options have additional information in tooltips.', 'info')
|
||||||
if self.startNumber < 5:
|
if self.startNumber < 5:
|
||||||
self.addMessage('Since you are new user of <b>KCC</b> please see few '
|
self.addMessage('Since you are a new user of <b>KCC</b> please see few '
|
||||||
'<a href="https://github.com/ciromattia/kcc/wiki/Important-tips">important tips</a>.',
|
'<a href="https://github.com/ciromattia/kcc/wiki/Important-tips">important tips</a>.',
|
||||||
'info')
|
'info')
|
||||||
rarExitCode = Popen('unrar', stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=True)
|
rarExitCode = Popen('unrar', stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=True)
|
||||||
@@ -1002,6 +1035,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
GUI.gammaSlider.valueChanged.connect(self.changeGamma)
|
GUI.gammaSlider.valueChanged.connect(self.changeGamma)
|
||||||
GUI.gammaBox.stateChanged.connect(self.togglegammaBox)
|
GUI.gammaBox.stateChanged.connect(self.togglegammaBox)
|
||||||
GUI.webtoonBox.stateChanged.connect(self.togglewebtoonBox)
|
GUI.webtoonBox.stateChanged.connect(self.togglewebtoonBox)
|
||||||
|
GUI.qualityBox.stateChanged.connect(self.togglequalityBox)
|
||||||
GUI.deviceBox.activated.connect(self.changeDevice)
|
GUI.deviceBox.activated.connect(self.changeDevice)
|
||||||
GUI.formatBox.activated.connect(self.changeFormat)
|
GUI.formatBox.activated.connect(self.changeFormat)
|
||||||
MW.progressBarTick.connect(self.updateProgressbar)
|
MW.progressBarTick.connect(self.updateProgressbar)
|
||||||
@@ -1085,7 +1119,10 @@ class KCCGUI_MetaEditor(KCC_ui_editor.Ui_editorDialog):
|
|||||||
for field in (self.writerLine, self.pencillerLine, self.inkerLine, self.coloristLine):
|
for field in (self.writerLine, self.pencillerLine, self.inkerLine, self.coloristLine):
|
||||||
field.setText(', '.join(self.parser.data[field.objectName().capitalize()[:-4] + 's']))
|
field.setText(', '.join(self.parser.data[field.objectName().capitalize()[:-4] + 's']))
|
||||||
if self.seriesLine.text() == '':
|
if self.seriesLine.text() == '':
|
||||||
self.seriesLine.setText(file.split('\\')[-1].split('/')[-1].split('.')[0])
|
if file.endswith('.xml'):
|
||||||
|
self.seriesLine.setText(file.split('\\')[-2])
|
||||||
|
else:
|
||||||
|
self.seriesLine.setText(file.split('\\')[-1].split('/')[-1].split('.')[0])
|
||||||
|
|
||||||
def saveData(self):
|
def saveData(self):
|
||||||
for field in (self.volumeLine, self.numberLine, self.muidLine):
|
for field in (self.volumeLine, self.numberLine, self.muidLine):
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
# Form implementation generated from reading ui file 'gui\KCC.ui'
|
# Form implementation generated from reading ui file 'gui\KCC.ui'
|
||||||
#
|
#
|
||||||
# Created by: PyQt5 UI code generator 5.6
|
# Created by: PyQt5 UI code generator 5.8.1
|
||||||
#
|
#
|
||||||
# WARNING! All changes made in this file will be lost!
|
# WARNING! All changes made in this file will be lost!
|
||||||
|
|
||||||
@@ -81,6 +81,7 @@ class Ui_mainWindow(object):
|
|||||||
self.rotateBox.setObjectName("rotateBox")
|
self.rotateBox.setObjectName("rotateBox")
|
||||||
self.gridLayout_2.addWidget(self.rotateBox, 0, 1, 1, 1)
|
self.gridLayout_2.addWidget(self.rotateBox, 0, 1, 1, 1)
|
||||||
self.qualityBox = QtWidgets.QCheckBox(self.optionWidget)
|
self.qualityBox = QtWidgets.QCheckBox(self.optionWidget)
|
||||||
|
self.qualityBox.setTristate(True)
|
||||||
self.qualityBox.setObjectName("qualityBox")
|
self.qualityBox.setObjectName("qualityBox")
|
||||||
self.gridLayout_2.addWidget(self.qualityBox, 0, 2, 1, 1)
|
self.gridLayout_2.addWidget(self.qualityBox, 0, 2, 1, 1)
|
||||||
self.webtoonBox = QtWidgets.QCheckBox(self.optionWidget)
|
self.webtoonBox = QtWidgets.QCheckBox(self.optionWidget)
|
||||||
@@ -231,32 +232,33 @@ class Ui_mainWindow(object):
|
|||||||
def retranslateUi(self, mainWindow):
|
def retranslateUi(self, mainWindow):
|
||||||
_translate = QtCore.QCoreApplication.translate
|
_translate = QtCore.QCoreApplication.translate
|
||||||
mainWindow.setWindowTitle(_translate("mainWindow", "Kindle Comic Converter"))
|
mainWindow.setWindowTitle(_translate("mainWindow", "Kindle Comic Converter"))
|
||||||
self.hLabel.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Resolution of target device.</p></body></html>"))
|
self.hLabel.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Resolution of the target device.</p></body></html>"))
|
||||||
self.hLabel.setText(_translate("mainWindow", "Custom height:"))
|
self.hLabel.setText(_translate("mainWindow", "Custom height:"))
|
||||||
self.widthBox.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Resolution of target device.</p></body></html>"))
|
self.widthBox.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Resolution of the target device.</p></body></html>"))
|
||||||
self.wLabel.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Resolution of target device.</p></body></html>"))
|
self.wLabel.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Resolution of the target device.</p></body></html>"))
|
||||||
self.wLabel.setText(_translate("mainWindow", "Custom width:"))
|
self.wLabel.setText(_translate("mainWindow", "Custom width:"))
|
||||||
self.heightBox.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Resolution of target device.</p></body></html>"))
|
self.heightBox.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Resolution of the target device.</p></body></html>"))
|
||||||
self.mangaBox.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Enable right-to-left reading.</p></body></html>"))
|
self.mangaBox.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Enable right-to-left reading.</p></body></html>"))
|
||||||
self.mangaBox.setText(_translate("mainWindow", "Manga mode"))
|
self.mangaBox.setText(_translate("mainWindow", "Manga mode"))
|
||||||
self.rotateBox.setToolTip(_translate("mainWindow", "<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Split<br/></span>Double page spreads will be cut into two separate pages.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - Rotate and split<br/></span>Double page spreads will be displayed twice. First rotated and then split. </p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Rotate<br/></span>Double page spreads will be rotated.</p></body></html>"))
|
self.rotateBox.setToolTip(_translate("mainWindow", "<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Split<br/></span>Double page spreads will be cut into two separate pages.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - Rotate and split<br/></span>Double page spreads will be displayed twice. First rotated and then split. </p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Rotate<br/></span>Double page spreads will be rotated.</p></body></html>"))
|
||||||
self.rotateBox.setText(_translate("mainWindow", "Spread splitter"))
|
self.rotateBox.setText(_translate("mainWindow", "Spread splitter"))
|
||||||
self.qualityBox.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - 4 panels<br/></span>Zoom each corner separately.</p><p style=\'white-space:pre\'><span style=\" font-weight:600; text-decoration: underline;\">Checked - 2 panels<br/></span>Zoom only the top and bottom of the page.</p></body></html>"))
|
self.qualityBox.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - 4 panels<br/></span>Zoom each corner separately.</p><p style=\'white-space:pre\'><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - 2 panels<br/></span>Zoom only the top and bottom of the page.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - 4 high-quality panels<br/></span>Zoom each corner separately. Try to increase the quality of magnification. Check wiki for more details.</p></body></html>"))
|
||||||
self.qualityBox.setText(_translate("mainWindow", "Panel View 4/2"))
|
self.qualityBox.setText(_translate("mainWindow", "Panel View 4/2/HQ"))
|
||||||
self.webtoonBox.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Enable special parsing mode for Korean Webtoons.</p></body></html>"))
|
self.webtoonBox.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Enable special parsing mode for Korean Webtoons.</p></body></html>"))
|
||||||
self.webtoonBox.setText(_translate("mainWindow", "Webtoon mode"))
|
self.webtoonBox.setText(_translate("mainWindow", "Webtoon mode"))
|
||||||
self.upscaleBox.setToolTip(_translate("mainWindow", "<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.setToolTip(_translate("mainWindow", "<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("mainWindow", "Stretch/Upscale"))
|
self.upscaleBox.setText(_translate("mainWindow", "Stretch/Upscale"))
|
||||||
self.gammaBox.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Disable automatic gamma correction.</p></body></html>"))
|
self.gammaBox.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Disable automatic gamma correction.</p></body></html>"))
|
||||||
self.gammaBox.setText(_translate("mainWindow", "Custom gamma"))
|
self.gammaBox.setText(_translate("mainWindow", "Custom gamma"))
|
||||||
self.borderBox.setToolTip(_translate("mainWindow", "<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.setToolTip(_translate("mainWindow", "<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Autodetection<br/></span>The 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("mainWindow", "W/B margins"))
|
self.borderBox.setText(_translate("mainWindow", "W/B margins"))
|
||||||
self.outputSplit.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Automatic mode<br/></span>Output will be splitted automatically.</p><p style=\'white-space:pre\'><span style=\" font-weight:600; text-decoration: underline;\">Checked - Volume mode<br/></span>Every subdirectory will be considered as separate volume.</p></body></html>"))
|
self.outputSplit.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Automatic mode<br/></span>The output will be split automatically.</p><p style=\'white-space:pre\'><span style=\" font-weight:600; text-decoration: underline;\">Checked - Volume mode<br/></span>Every subdirectory will be considered as a separate volume.</p></body></html>"))
|
||||||
self.outputSplit.setText(_translate("mainWindow", "Output split"))
|
self.outputSplit.setText(_translate("mainWindow", "Output split"))
|
||||||
self.colorBox.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Disable conversion to grayscale.</p></body></html>"))
|
self.colorBox.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Disable conversion to grayscale.</p></body></html>"))
|
||||||
self.colorBox.setText(_translate("mainWindow", "Color mode"))
|
self.colorBox.setText(_translate("mainWindow", "Color mode"))
|
||||||
self.gammaLabel.setText(_translate("mainWindow", "Gamma: Auto"))
|
self.gammaLabel.setText(_translate("mainWindow", "Gamma: Auto"))
|
||||||
self.editorButton.setText(_translate("mainWindow", "Editor"))
|
self.editorButton.setText(_translate("mainWindow", "Editor"))
|
||||||
|
self.editorButton.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Shift+Click to edit directory.</p></body></html>"))
|
||||||
self.wikiButton.setText(_translate("mainWindow", "Wiki"))
|
self.wikiButton.setText(_translate("mainWindow", "Wiki"))
|
||||||
self.directoryButton.setToolTip(_translate("mainWindow", "<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.setToolTip(_translate("mainWindow", "<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("mainWindow", "Add directory"))
|
self.directoryButton.setText(_translate("mainWindow", "Add directory"))
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
__version__ = '5.3.0'
|
__version__ = '5.4.4'
|
||||||
__license__ = 'ISC'
|
__license__ = 'ISC'
|
||||||
__copyright__ = '2012-2017, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>'
|
__copyright__ = '2012-2018, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
||||||
# Copyright (c) 2013-2017 Pawel Jastrzebski <pawelj@iosphe.re>
|
# Copyright (c) 2013-2018 Pawel Jastrzebski <pawelj@iosphe.re>
|
||||||
#
|
#
|
||||||
# Permission to use, copy, modify, and/or distribute this software for
|
# Permission to use, copy, modify, and/or distribute this software for
|
||||||
# any purpose with or without fee is hereby granted, provided that the
|
# any purpose with or without fee is hereby granted, provided that the
|
||||||
@@ -16,28 +16,23 @@
|
|||||||
# PERFORMANCE OF THIS SOFTWARE.
|
# PERFORMANCE OF THIS SOFTWARE.
|
||||||
#
|
#
|
||||||
|
|
||||||
import sys
|
|
||||||
import os
|
import os
|
||||||
from zipfile import is_zipfile, ZipFile
|
from zipfile import is_zipfile, ZipFile
|
||||||
from subprocess import STDOUT, PIPE
|
from subprocess import STDOUT, PIPE
|
||||||
from psutil import Popen
|
from psutil import Popen
|
||||||
from shutil import move, copy
|
from shutil import move
|
||||||
try:
|
|
||||||
from scandir import walk
|
|
||||||
except ImportError:
|
|
||||||
walk = os.walk
|
|
||||||
from . import rarfile
|
from . import rarfile
|
||||||
from .shared import check7ZFile as is_7zfile, saferReplace, saferRemove
|
from .shared import check7ZFile as is_7zfile
|
||||||
|
|
||||||
|
|
||||||
class CBxArchive:
|
class CBxArchive:
|
||||||
def __init__(self, origFileName):
|
def __init__(self, fname):
|
||||||
self.origFileName = origFileName
|
self.fname = fname
|
||||||
if is_zipfile(origFileName):
|
if is_zipfile(fname):
|
||||||
self.compressor = 'zip'
|
self.compressor = 'zip'
|
||||||
elif rarfile.is_rarfile(origFileName):
|
elif rarfile.is_rarfile(fname):
|
||||||
self.compressor = 'rar'
|
self.compressor = 'rar'
|
||||||
elif is_7zfile(origFileName):
|
elif is_7zfile(fname):
|
||||||
self.compressor = '7z'
|
self.compressor = '7z'
|
||||||
else:
|
else:
|
||||||
self.compressor = None
|
self.compressor = None
|
||||||
@@ -46,41 +41,32 @@ class CBxArchive:
|
|||||||
return self.compressor is not None
|
return self.compressor is not None
|
||||||
|
|
||||||
def extractCBZ(self, targetdir):
|
def extractCBZ(self, targetdir):
|
||||||
cbzFile = ZipFile(self.origFileName)
|
cbzFile = ZipFile(self.fname)
|
||||||
filelist = []
|
filelist = []
|
||||||
for f in cbzFile.namelist():
|
for f in cbzFile.namelist():
|
||||||
if f.startswith('__MACOSX') or f.endswith('.DS_Store') or f.endswith('humbs.db'):
|
if f.startswith('__MACOSX') or f.endswith('.DS_Store') or f.endswith('humbs.db'):
|
||||||
pass # skip MacOS special files
|
pass
|
||||||
elif f.endswith('/'):
|
elif f.endswith('/'):
|
||||||
try:
|
os.makedirs(os.path.join(targetdir, f), exist_ok=True)
|
||||||
os.makedirs(os.path.join(targetdir, f))
|
|
||||||
except Exception:
|
|
||||||
pass # the dir exists so we are going to extract the images only.
|
|
||||||
else:
|
else:
|
||||||
filelist.append(f)
|
filelist.append(f)
|
||||||
cbzFile.extractall(targetdir, filelist)
|
cbzFile.extractall(targetdir, filelist)
|
||||||
|
|
||||||
def extractCBR(self, targetdir):
|
def extractCBR(self, targetdir):
|
||||||
cbrFile = rarfile.RarFile(self.origFileName)
|
cbrFile = rarfile.RarFile(self.fname)
|
||||||
cbrFile.extractall(targetdir)
|
cbrFile.extractall(targetdir)
|
||||||
for root, dirnames, filenames in walk(targetdir):
|
for root, _, filenames in os.walk(targetdir):
|
||||||
for filename in filenames:
|
for filename in filenames:
|
||||||
if filename.startswith('__MACOSX') or filename.endswith('.DS_Store') or filename.endswith('humbs.db'):
|
if filename.startswith('__MACOSX') or filename.endswith('.DS_Store') or filename.endswith('humbs.db'):
|
||||||
saferRemove(os.path.join(root, filename))
|
os.remove(os.path.join(root, filename))
|
||||||
|
|
||||||
def extractCB7(self, targetdir):
|
def extractCB7(self, targetdir):
|
||||||
# Workaround for some wide UTF-8 + Popen abnormalities
|
output = Popen('7za x "' + self.fname + '" -xr!__MACOSX -xr!.DS_Store -xr!thumbs.db -xr!Thumbs.db -o"' +
|
||||||
if sys.platform.startswith('darwin'):
|
|
||||||
copy(self.origFileName, os.path.join(os.path.dirname(self.origFileName), 'TMP_KCC_TMP'))
|
|
||||||
self.origFileName = os.path.join(os.path.dirname(self.origFileName), 'TMP_KCC_TMP')
|
|
||||||
output = Popen('7za x "' + self.origFileName + '" -xr!__MACOSX -xr!.DS_Store -xr!thumbs.db -xr!Thumbs.db -o"' +
|
|
||||||
targetdir + '"', stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=True)
|
targetdir + '"', stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=True)
|
||||||
extracted = False
|
extracted = False
|
||||||
for line in output.stdout:
|
for line in output.stdout:
|
||||||
if b"Everything is Ok" in line:
|
if b"Everything is Ok" in line:
|
||||||
extracted = True
|
extracted = True
|
||||||
if sys.platform.startswith('darwin'):
|
|
||||||
saferRemove(self.origFileName)
|
|
||||||
if not extracted:
|
if not extracted:
|
||||||
raise OSError
|
raise OSError
|
||||||
|
|
||||||
@@ -96,10 +82,6 @@ class CBxArchive:
|
|||||||
adir.remove('ComicInfo.xml')
|
adir.remove('ComicInfo.xml')
|
||||||
if len(adir) == 1 and os.path.isdir(os.path.join(targetdir, adir[0])):
|
if len(adir) == 1 and os.path.isdir(os.path.join(targetdir, adir[0])):
|
||||||
for f in os.listdir(os.path.join(targetdir, adir[0])):
|
for f in os.listdir(os.path.join(targetdir, adir[0])):
|
||||||
# If directory names contain UTF-8 chars shutil.move can't clean up the mess alone
|
|
||||||
if os.path.isdir(os.path.join(targetdir, f)):
|
|
||||||
saferReplace(os.path.join(targetdir, adir[0], f), os.path.join(targetdir, adir[0], f + '-A'))
|
|
||||||
f += '-A'
|
|
||||||
move(os.path.join(targetdir, adir[0], f), targetdir)
|
move(os.path.join(targetdir, adir[0], f), targetdir)
|
||||||
os.rmdir(os.path.join(targetdir, adir[0]))
|
os.rmdir(os.path.join(targetdir, adir[0]))
|
||||||
return targetdir
|
return targetdir
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
||||||
# Copyright (c) 2013-2017 Pawel Jastrzebski <pawelj@iosphe.re>
|
# Copyright (c) 2013-2018 Pawel Jastrzebski <pawelj@iosphe.re>
|
||||||
#
|
#
|
||||||
# Permission to use, copy, modify, and/or distribute this software for
|
# Permission to use, copy, modify, and/or distribute this software for
|
||||||
# any purpose with or without fee is hereby granted, provided that the
|
# any purpose with or without fee is hereby granted, provided that the
|
||||||
@@ -36,17 +36,13 @@ from uuid import uuid4
|
|||||||
from slugify import slugify as slugifyExt
|
from slugify import slugify as slugifyExt
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
from subprocess import STDOUT, PIPE
|
from subprocess import STDOUT, PIPE
|
||||||
from psutil import Popen, virtual_memory
|
from psutil import Popen, virtual_memory, disk_usage
|
||||||
from html import escape
|
from html import escape
|
||||||
try:
|
try:
|
||||||
from PyQt5 import QtCore
|
from PyQt5 import QtCore
|
||||||
except ImportError:
|
except ImportError:
|
||||||
QtCore = None
|
QtCore = None
|
||||||
try:
|
from .shared import md5Checksum, getImageFileName, walkSort, walkLevel, sanitizeTrace
|
||||||
from scandir import walk
|
|
||||||
except ImportError:
|
|
||||||
walk = os.walk
|
|
||||||
from .shared import md5Checksum, getImageFileName, walkSort, walkLevel, saferReplace, saferRemove, sanitizeTrace
|
|
||||||
from . import comic2panel
|
from . import comic2panel
|
||||||
from . import image
|
from . import image
|
||||||
from . import cbxarchive
|
from . import cbxarchive
|
||||||
@@ -85,14 +81,14 @@ def buildHTML(path, imgfile, imgfilepath):
|
|||||||
imgfilepath = md5Checksum(imgfilepath)
|
imgfilepath = md5Checksum(imgfilepath)
|
||||||
filename = getImageFileName(imgfile)
|
filename = getImageFileName(imgfile)
|
||||||
deviceres = options.profileData[1]
|
deviceres = options.profileData[1]
|
||||||
if "Rotated" in options.imgIndex[imgfilepath]:
|
if "Rotated" in options.imgMetadata[imgfilepath]:
|
||||||
rotatedPage = True
|
rotatedPage = True
|
||||||
else:
|
else:
|
||||||
rotatedPage = False
|
rotatedPage = False
|
||||||
if "BlackFill" in options.imgIndex[imgfilepath]:
|
if "BlackBackground" in options.imgMetadata[imgfilepath]:
|
||||||
additionalStyle = 'background-color:#000000;'
|
additionalStyle = 'background-color:#000000;'
|
||||||
else:
|
else:
|
||||||
additionalStyle = 'background-color:#FFFFFF;'
|
additionalStyle = ''
|
||||||
postfix = ''
|
postfix = ''
|
||||||
backref = 1
|
backref = 1
|
||||||
head = path
|
head = path
|
||||||
@@ -107,6 +103,10 @@ def buildHTML(path, imgfile, imgfilepath):
|
|||||||
os.makedirs(htmlpath)
|
os.makedirs(htmlpath)
|
||||||
htmlfile = os.path.join(htmlpath, filename[0] + '.xhtml')
|
htmlfile = os.path.join(htmlpath, filename[0] + '.xhtml')
|
||||||
imgsize = Image.open(os.path.join(head, "Images", postfix, imgfile)).size
|
imgsize = Image.open(os.path.join(head, "Images", postfix, imgfile)).size
|
||||||
|
if options.hq:
|
||||||
|
imgsizeframe = (int(imgsize[0] // 1.5), int(imgsize[1] // 1.5))
|
||||||
|
else:
|
||||||
|
imgsizeframe = imgsize
|
||||||
f = open(htmlfile, "w", encoding='UTF-8')
|
f = open(htmlfile, "w", encoding='UTF-8')
|
||||||
f.writelines(["<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n",
|
f.writelines(["<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n",
|
||||||
"<!DOCTYPE html>\n",
|
"<!DOCTYPE html>\n",
|
||||||
@@ -115,17 +115,20 @@ def buildHTML(path, imgfile, imgfilepath):
|
|||||||
"<title>", escape(filename[0]), "</title>\n",
|
"<title>", escape(filename[0]), "</title>\n",
|
||||||
"<link href=\"", "../" * (backref - 1), "style.css\" type=\"text/css\" rel=\"stylesheet\"/>\n",
|
"<link href=\"", "../" * (backref - 1), "style.css\" type=\"text/css\" rel=\"stylesheet\"/>\n",
|
||||||
"<meta name=\"viewport\" "
|
"<meta name=\"viewport\" "
|
||||||
"content=\"width=" + str(deviceres[0]) + ", height=" + str(deviceres[1]) + "\"/>\n"
|
"content=\"width=" + str(imgsize[0]) + ", height=" + str(imgsize[1]) + "\"/>\n"
|
||||||
"</head>\n",
|
"</head>\n",
|
||||||
"<body style=\"" + additionalStyle + "\">\n",
|
"<body style=\"" + additionalStyle + "\">\n",
|
||||||
"<div style=\"text-align:center;top:" + getTopMargin(deviceres, imgsize) + "%;\">\n",
|
"<div style=\"text-align:center;top:" + getTopMargin(deviceres, imgsizeframe) + "%;\">\n",
|
||||||
"<img width=\"" + str(imgsize[0]) + "\" height=\"" + str(imgsize[1]) + "\" ",
|
"<img width=\"" + str(imgsizeframe[0]) + "\" height=\"" + str(imgsizeframe[1]) + "\" ",
|
||||||
"src=\"", "../" * backref, "Images/", postfix, imgfile, "\"/>\n</div>\n"])
|
"src=\"", "../" * backref, "Images/", postfix, imgfile, "\"/>\n</div>\n"])
|
||||||
if options.iskindle and options.panelview:
|
if options.iskindle and options.panelview:
|
||||||
if options.autoscale:
|
if options.autoscale:
|
||||||
size = (getPanelViewResolution(imgsize, deviceres))
|
size = (getPanelViewResolution(imgsize, deviceres))
|
||||||
else:
|
else:
|
||||||
size = (int(imgsize[0] * 1.5), int(imgsize[1] * 1.5))
|
if options.hq:
|
||||||
|
size = imgsize
|
||||||
|
else:
|
||||||
|
size = (int(imgsize[0] * 1.5), int(imgsize[1] * 1.5))
|
||||||
if size[0] - deviceres[0] < deviceres[0] * 0.01:
|
if size[0] - deviceres[0] < deviceres[0] * 0.01:
|
||||||
noHorizontalPV = True
|
noHorizontalPV = True
|
||||||
else:
|
else:
|
||||||
@@ -195,7 +198,7 @@ def buildHTML(path, imgfile, imgfilepath):
|
|||||||
return path, imgfile
|
return path, imgfile
|
||||||
|
|
||||||
|
|
||||||
def buildNCX(dstdir, title, chapters, chapterNames):
|
def buildNCX(dstdir, title, chapters, chapternames):
|
||||||
ncxfile = os.path.join(dstdir, 'OEBPS', 'toc.ncx')
|
ncxfile = os.path.join(dstdir, 'OEBPS', 'toc.ncx')
|
||||||
f = open(ncxfile, "w", encoding='UTF-8')
|
f = open(ncxfile, "w", encoding='UTF-8')
|
||||||
f.writelines(["<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n",
|
f.writelines(["<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n",
|
||||||
@@ -214,10 +217,10 @@ def buildNCX(dstdir, title, chapters, chapterNames):
|
|||||||
filename = getImageFileName(os.path.join(folder, chapter[1]))
|
filename = getImageFileName(os.path.join(folder, chapter[1]))
|
||||||
navID = folder.replace('/', '_').replace('\\', '_')
|
navID = folder.replace('/', '_').replace('\\', '_')
|
||||||
if options.chapters:
|
if options.chapters:
|
||||||
title = chapterNames[chapter[1]]
|
title = chapternames[chapter[1]]
|
||||||
navID = filename[0].replace('/', '_').replace('\\', '_')
|
navID = filename[0].replace('/', '_').replace('\\', '_')
|
||||||
elif os.path.basename(folder) != "Text":
|
elif os.path.basename(folder) != "Text":
|
||||||
title = chapterNames[os.path.basename(folder)]
|
title = chapternames[os.path.basename(folder)]
|
||||||
f.write("<navPoint id=\"" + navID + "\"><navLabel><text>" +
|
f.write("<navPoint id=\"" + navID + "\"><navLabel><text>" +
|
||||||
escape(title) + "</text></navLabel><content src=\"" + filename[0].replace("\\", "/") +
|
escape(title) + "</text></navLabel><content src=\"" + filename[0].replace("\\", "/") +
|
||||||
".xhtml\"/></navPoint>\n")
|
".xhtml\"/></navPoint>\n")
|
||||||
@@ -225,7 +228,7 @@ def buildNCX(dstdir, title, chapters, chapterNames):
|
|||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
|
|
||||||
def buildNAV(dstdir, title, chapters, chapterNames):
|
def buildNAV(dstdir, title, chapters, chapternames):
|
||||||
navfile = os.path.join(dstdir, 'OEBPS', 'nav.xhtml')
|
navfile = os.path.join(dstdir, 'OEBPS', 'nav.xhtml')
|
||||||
f = open(navfile, "w", encoding='UTF-8')
|
f = open(navfile, "w", encoding='UTF-8')
|
||||||
f.writelines(["<?xml version=\"1.0\" encoding=\"utf-8\"?>\n",
|
f.writelines(["<?xml version=\"1.0\" encoding=\"utf-8\"?>\n",
|
||||||
@@ -242,9 +245,9 @@ def buildNAV(dstdir, title, chapters, chapterNames):
|
|||||||
folder = chapter[0].replace(os.path.join(dstdir, 'OEBPS'), '').lstrip('/').lstrip('\\\\')
|
folder = chapter[0].replace(os.path.join(dstdir, 'OEBPS'), '').lstrip('/').lstrip('\\\\')
|
||||||
filename = getImageFileName(os.path.join(folder, chapter[1]))
|
filename = getImageFileName(os.path.join(folder, chapter[1]))
|
||||||
if options.chapters:
|
if options.chapters:
|
||||||
title = chapterNames[chapter[1]]
|
title = chapternames[chapter[1]]
|
||||||
elif os.path.basename(folder) != "Text":
|
elif os.path.basename(folder) != "Text":
|
||||||
title = chapterNames[os.path.basename(folder)]
|
title = chapternames[os.path.basename(folder)]
|
||||||
f.write("<li><a href=\"" + filename[0].replace("\\", "/") + ".xhtml\">" + escape(title) + "</a></li>\n")
|
f.write("<li><a href=\"" + filename[0].replace("\\", "/") + ".xhtml\">" + escape(title) + "</a></li>\n")
|
||||||
f.writelines(["</ol>\n",
|
f.writelines(["</ol>\n",
|
||||||
"</nav>\n",
|
"</nav>\n",
|
||||||
@@ -254,9 +257,9 @@ def buildNAV(dstdir, title, chapters, chapterNames):
|
|||||||
folder = chapter[0].replace(os.path.join(dstdir, 'OEBPS'), '').lstrip('/').lstrip('\\\\')
|
folder = chapter[0].replace(os.path.join(dstdir, 'OEBPS'), '').lstrip('/').lstrip('\\\\')
|
||||||
filename = getImageFileName(os.path.join(folder, chapter[1]))
|
filename = getImageFileName(os.path.join(folder, chapter[1]))
|
||||||
if options.chapters:
|
if options.chapters:
|
||||||
title = chapterNames[chapter[1]]
|
title = chapternames[chapter[1]]
|
||||||
elif os.path.basename(folder) != "Text":
|
elif os.path.basename(folder) != "Text":
|
||||||
title = chapterNames[os.path.basename(folder)]
|
title = chapternames[os.path.basename(folder)]
|
||||||
f.write("<li><a href=\"" + filename[0].replace("\\", "/") + ".xhtml\">" + escape(title) + "</a></li>\n")
|
f.write("<li><a href=\"" + filename[0].replace("\\", "/") + ".xhtml\">" + escape(title) + "</a></li>\n")
|
||||||
f.write("</ol>\n</nav>\n</body>\n</html>")
|
f.write("</ol>\n</nav>\n</body>\n</html>")
|
||||||
f.close()
|
f.close()
|
||||||
@@ -284,20 +287,27 @@ def buildOPF(dstdir, title, filelist, cover=None):
|
|||||||
for author in options.authors:
|
for author in options.authors:
|
||||||
f.writelines(["<dc:creator>", author, "</dc:creator>\n"])
|
f.writelines(["<dc:creator>", author, "</dc:creator>\n"])
|
||||||
f.writelines(["<meta property=\"dcterms:modified\">" + strftime("%Y-%m-%dT%H:%M:%SZ", gmtime()) + "</meta>\n",
|
f.writelines(["<meta property=\"dcterms:modified\">" + strftime("%Y-%m-%dT%H:%M:%SZ", gmtime()) + "</meta>\n",
|
||||||
"<meta name=\"cover\" content=\"cover\"/>\n",
|
"<meta name=\"cover\" content=\"cover\"/>\n"])
|
||||||
"<meta property=\"rendition:orientation\">portrait</meta>\n",
|
|
||||||
"<meta property=\"rendition:spread\">portrait</meta>\n",
|
|
||||||
"<meta property=\"rendition:layout\">pre-paginated</meta>\n"])
|
|
||||||
if options.iskindle and options.profile != 'Custom':
|
if options.iskindle and options.profile != 'Custom':
|
||||||
f.writelines(["<meta name=\"original-resolution\" content=\"",
|
f.writelines(["<meta name=\"fixed-layout\" content=\"true\"/>\n",
|
||||||
|
"<meta name=\"original-resolution\" content=\"",
|
||||||
str(deviceres[0]) + "x" + str(deviceres[1]) + "\"/>\n",
|
str(deviceres[0]) + "x" + str(deviceres[1]) + "\"/>\n",
|
||||||
"<meta name=\"book-type\" content=\"comic\"/>\n",
|
"<meta name=\"book-type\" content=\"comic\"/>\n",
|
||||||
"<meta name=\"RegionMagnification\" content=\"true\"/>\n",
|
|
||||||
"<meta name=\"primary-writing-mode\" content=\"" + writingmode + "\"/>\n",
|
"<meta name=\"primary-writing-mode\" content=\"" + writingmode + "\"/>\n",
|
||||||
"<meta name=\"zero-gutter\" content=\"true\"/>\n",
|
"<meta name=\"zero-gutter\" content=\"true\"/>\n",
|
||||||
"<meta name=\"zero-margin\" content=\"true\"/>\n",
|
"<meta name=\"zero-margin\" content=\"true\"/>\n",
|
||||||
"<meta name=\"ke-border-color\" content=\"#ffffff\"/>\n",
|
"<meta name=\"ke-border-color\" content=\"#FFFFFF\"/>\n",
|
||||||
"<meta name=\"ke-border-width\" content=\"0\"/>\n"])
|
"<meta name=\"ke-border-width\" content=\"0\"/>\n"])
|
||||||
|
if options.kfx:
|
||||||
|
f.writelines(["<meta name=\"orientation-lock\" content=\"none\"/>\n",
|
||||||
|
"<meta name=\"region-mag\" content=\"false\"/>\n"])
|
||||||
|
else:
|
||||||
|
f.writelines(["<meta name=\"orientation-lock\" content=\"portrait\"/>\n",
|
||||||
|
"<meta name=\"region-mag\" content=\"true\"/>\n"])
|
||||||
|
else:
|
||||||
|
f.writelines(["<meta property=\"rendition:orientation\">portrait</meta>\n",
|
||||||
|
"<meta property=\"rendition:spread\">portrait</meta>\n",
|
||||||
|
"<meta property=\"rendition:layout\">pre-paginated</meta>\n"])
|
||||||
f.writelines(["</metadata>\n<manifest>\n<item id=\"ncx\" href=\"toc.ncx\" ",
|
f.writelines(["</metadata>\n<manifest>\n<item id=\"ncx\" href=\"toc.ncx\" ",
|
||||||
"media-type=\"application/x-dtbncx+xml\"/>\n",
|
"media-type=\"application/x-dtbncx+xml\"/>\n",
|
||||||
"<item id=\"nav\" href=\"nav.xhtml\" ",
|
"<item id=\"nav\" href=\"nav.xhtml\" ",
|
||||||
@@ -328,10 +338,43 @@ def buildOPF(dstdir, title, filelist, cover=None):
|
|||||||
f.write("<item id=\"css\" href=\"Text/style.css\" media-type=\"text/css\"/>\n")
|
f.write("<item id=\"css\" href=\"Text/style.css\" media-type=\"text/css\"/>\n")
|
||||||
if options.righttoleft:
|
if options.righttoleft:
|
||||||
f.write("</manifest>\n<spine page-progression-direction=\"rtl\" toc=\"ncx\">\n")
|
f.write("</manifest>\n<spine page-progression-direction=\"rtl\" toc=\"ncx\">\n")
|
||||||
|
pageside = "right"
|
||||||
else:
|
else:
|
||||||
f.write("</manifest>\n<spine page-progression-direction=\"ltr\" toc=\"ncx\">\n")
|
f.write("</manifest>\n<spine page-progression-direction=\"ltr\" toc=\"ncx\">\n")
|
||||||
for entry in reflist:
|
pageside = "left"
|
||||||
f.write("<itemref idref=\"page_" + entry + "\"/>\n")
|
if options.iskindle:
|
||||||
|
for entry in reflist:
|
||||||
|
if options.righttoleft:
|
||||||
|
if entry.endswith("-b"):
|
||||||
|
f.write("<itemref idref=\"page_" + entry + "\" linear=\"yes\" properties=\"page-spread-right\"/>\n")
|
||||||
|
pageside = "right"
|
||||||
|
elif entry.endswith("-c"):
|
||||||
|
f.write("<itemref idref=\"page_" + entry + "\" linear=\"yes\" properties=\"page-spread-left\"/>\n")
|
||||||
|
pageside = "right"
|
||||||
|
else:
|
||||||
|
f.write("<itemref idref=\"page_" + entry + "\" linear=\"yes\" properties=\"page-spread-" +
|
||||||
|
pageside + "\"/>\n")
|
||||||
|
if pageside == "right":
|
||||||
|
pageside = "left"
|
||||||
|
else:
|
||||||
|
pageside = "right"
|
||||||
|
else:
|
||||||
|
if entry.endswith("-b"):
|
||||||
|
f.write("<itemref idref=\"page_" + entry + "\" linear=\"yes\" properties=\"page-spread-left\"/>\n")
|
||||||
|
pageside = "left"
|
||||||
|
elif entry.endswith("-c"):
|
||||||
|
f.write("<itemref idref=\"page_" + entry + "\" linear=\"yes\" properties=\"page-spread-right\"/>\n")
|
||||||
|
pageside = "left"
|
||||||
|
else:
|
||||||
|
f.write("<itemref idref=\"page_" + entry + "\" linear=\"yes\" properties=\"page-spread-" +
|
||||||
|
pageside + "\"/>\n")
|
||||||
|
if pageside == "right":
|
||||||
|
pageside = "left"
|
||||||
|
else:
|
||||||
|
pageside = "right"
|
||||||
|
else:
|
||||||
|
for entry in reflist:
|
||||||
|
f.write("<itemref idref=\"page_" + entry + "\">\n")
|
||||||
f.write("</spine>\n</package>\n")
|
f.write("</spine>\n</package>\n")
|
||||||
f.close()
|
f.close()
|
||||||
os.mkdir(os.path.join(dstdir, 'META-INF'))
|
os.mkdir(os.path.join(dstdir, 'META-INF'))
|
||||||
@@ -345,7 +388,7 @@ def buildOPF(dstdir, title, filelist, cover=None):
|
|||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
|
|
||||||
def buildEPUB(path, chapterNames, tomeNumber):
|
def buildEPUB(path, chapternames, tomenumber):
|
||||||
filelist = []
|
filelist = []
|
||||||
chapterlist = []
|
chapterlist = []
|
||||||
cover = None
|
cover = None
|
||||||
@@ -358,73 +401,74 @@ def buildEPUB(path, chapterNames, tomeNumber):
|
|||||||
"display: block;\n",
|
"display: block;\n",
|
||||||
"margin: 0;\n",
|
"margin: 0;\n",
|
||||||
"padding: 0;\n",
|
"padding: 0;\n",
|
||||||
"}\n",
|
|
||||||
"#PV {\n",
|
|
||||||
"position: absolute;\n",
|
|
||||||
"width: 100%;\n",
|
|
||||||
"height: 100%;\n",
|
|
||||||
"top: 0;\n",
|
|
||||||
"left: 0;\n",
|
|
||||||
"}\n",
|
|
||||||
"#PV-T {\n",
|
|
||||||
"top: 0;\n",
|
|
||||||
"width: 100%;\n",
|
|
||||||
"height: 50%;\n",
|
|
||||||
"}\n",
|
|
||||||
"#PV-B {\n",
|
|
||||||
"bottom: 0;\n",
|
|
||||||
"width: 100%;\n",
|
|
||||||
"height: 50%;\n",
|
|
||||||
"}\n",
|
|
||||||
"#PV-L {\n",
|
|
||||||
"left: 0;\n",
|
|
||||||
"width: 49.5%;\n",
|
|
||||||
"height: 100%;\n",
|
|
||||||
"float: left;\n",
|
|
||||||
"}\n",
|
|
||||||
"#PV-R {\n",
|
|
||||||
"right: 0;\n",
|
|
||||||
"width: 49.5%;\n",
|
|
||||||
"height: 100%;\n",
|
|
||||||
"float: right;\n",
|
|
||||||
"}\n",
|
|
||||||
"#PV-TL {\n",
|
|
||||||
"top: 0;\n",
|
|
||||||
"left: 0;\n",
|
|
||||||
"width: 49.5%;\n",
|
|
||||||
"height: 50%;\n",
|
|
||||||
"float: left;\n",
|
|
||||||
"}\n",
|
|
||||||
"#PV-TR {\n",
|
|
||||||
"top: 0;\n",
|
|
||||||
"right: 0;\n",
|
|
||||||
"width: 49.5%;\n",
|
|
||||||
"height: 50%;\n",
|
|
||||||
"float: right;\n",
|
|
||||||
"}\n",
|
|
||||||
"#PV-BL {\n",
|
|
||||||
"bottom: 0;\n",
|
|
||||||
"left: 0;\n",
|
|
||||||
"width: 49.5%;\n",
|
|
||||||
"height: 50%;\n",
|
|
||||||
"float: left;\n",
|
|
||||||
"}\n",
|
|
||||||
"#PV-BR {\n",
|
|
||||||
"bottom: 0;\n",
|
|
||||||
"right: 0;\n",
|
|
||||||
"width: 49.5%;\n",
|
|
||||||
"height: 50%;\n",
|
|
||||||
"float: right;\n",
|
|
||||||
"}\n",
|
|
||||||
".PV-P {\n",
|
|
||||||
"width: 100%;\n",
|
|
||||||
"height: 100%;\n",
|
|
||||||
"top: 0;\n",
|
|
||||||
"position: absolute;\n",
|
|
||||||
"display: none;\n",
|
|
||||||
"}\n"])
|
"}\n"])
|
||||||
|
if options.iskindle and options.panelview:
|
||||||
|
f.writelines(["#PV {\n",
|
||||||
|
"position: absolute;\n",
|
||||||
|
"width: 100%;\n",
|
||||||
|
"height: 100%;\n",
|
||||||
|
"top: 0;\n",
|
||||||
|
"left: 0;\n",
|
||||||
|
"}\n",
|
||||||
|
"#PV-T {\n",
|
||||||
|
"top: 0;\n",
|
||||||
|
"width: 100%;\n",
|
||||||
|
"height: 50%;\n",
|
||||||
|
"}\n",
|
||||||
|
"#PV-B {\n",
|
||||||
|
"bottom: 0;\n",
|
||||||
|
"width: 100%;\n",
|
||||||
|
"height: 50%;\n",
|
||||||
|
"}\n",
|
||||||
|
"#PV-L {\n",
|
||||||
|
"left: 0;\n",
|
||||||
|
"width: 49.5%;\n",
|
||||||
|
"height: 100%;\n",
|
||||||
|
"float: left;\n",
|
||||||
|
"}\n",
|
||||||
|
"#PV-R {\n",
|
||||||
|
"right: 0;\n",
|
||||||
|
"width: 49.5%;\n",
|
||||||
|
"height: 100%;\n",
|
||||||
|
"float: right;\n",
|
||||||
|
"}\n",
|
||||||
|
"#PV-TL {\n",
|
||||||
|
"top: 0;\n",
|
||||||
|
"left: 0;\n",
|
||||||
|
"width: 49.5%;\n",
|
||||||
|
"height: 50%;\n",
|
||||||
|
"float: left;\n",
|
||||||
|
"}\n",
|
||||||
|
"#PV-TR {\n",
|
||||||
|
"top: 0;\n",
|
||||||
|
"right: 0;\n",
|
||||||
|
"width: 49.5%;\n",
|
||||||
|
"height: 50%;\n",
|
||||||
|
"float: right;\n",
|
||||||
|
"}\n",
|
||||||
|
"#PV-BL {\n",
|
||||||
|
"bottom: 0;\n",
|
||||||
|
"left: 0;\n",
|
||||||
|
"width: 49.5%;\n",
|
||||||
|
"height: 50%;\n",
|
||||||
|
"float: left;\n",
|
||||||
|
"}\n",
|
||||||
|
"#PV-BR {\n",
|
||||||
|
"bottom: 0;\n",
|
||||||
|
"right: 0;\n",
|
||||||
|
"width: 49.5%;\n",
|
||||||
|
"height: 50%;\n",
|
||||||
|
"float: right;\n",
|
||||||
|
"}\n",
|
||||||
|
".PV-P {\n",
|
||||||
|
"width: 100%;\n",
|
||||||
|
"height: 100%;\n",
|
||||||
|
"top: 0;\n",
|
||||||
|
"position: absolute;\n",
|
||||||
|
"display: none;\n",
|
||||||
|
"}\n"])
|
||||||
f.close()
|
f.close()
|
||||||
for (dirpath, dirnames, filenames) in walk(os.path.join(path, 'OEBPS', 'Images')):
|
for dirpath, dirnames, filenames in os.walk(os.path.join(path, 'OEBPS', 'Images')):
|
||||||
chapter = False
|
chapter = False
|
||||||
dirnames, filenames = walkSort(dirnames, filenames)
|
dirnames, filenames = walkSort(dirnames, filenames)
|
||||||
for afile in filenames:
|
for afile in filenames:
|
||||||
@@ -436,9 +480,9 @@ def buildEPUB(path, chapterNames, tomeNumber):
|
|||||||
cover = os.path.join(os.path.join(path, 'OEBPS', 'Images'),
|
cover = os.path.join(os.path.join(path, 'OEBPS', 'Images'),
|
||||||
'cover' + getImageFileName(filelist[-1][1])[1])
|
'cover' + getImageFileName(filelist[-1][1])[1])
|
||||||
options.covers.append((image.Cover(os.path.join(filelist[-1][0], filelist[-1][1]), cover, options,
|
options.covers.append((image.Cover(os.path.join(filelist[-1][0], filelist[-1][1]), cover, options,
|
||||||
tomeNumber), options.uuid))
|
tomenumber), options.uuid))
|
||||||
# Overwrite chapternames if tree is flat and ComicInfo.xml has bookmarks
|
# Overwrite chapternames if tree is flat and ComicInfo.xml has bookmarks
|
||||||
if not chapterNames and options.chapters:
|
if not chapternames and options.chapters:
|
||||||
chapterlist = []
|
chapterlist = []
|
||||||
globaldiff = 0
|
globaldiff = 0
|
||||||
for aChapter in options.chapters:
|
for aChapter in options.chapters:
|
||||||
@@ -450,22 +494,22 @@ def buildEPUB(path, chapterNames, tomeNumber):
|
|||||||
pageid -= 1
|
pageid -= 1
|
||||||
filename = filelist[pageid][1]
|
filename = filelist[pageid][1]
|
||||||
chapterlist.append((filelist[pageid][0].replace('Images', 'Text'), filename))
|
chapterlist.append((filelist[pageid][0].replace('Images', 'Text'), filename))
|
||||||
chapterNames[filename] = aChapter[1]
|
chapternames[filename] = aChapter[1]
|
||||||
globaldiff = pageid - (aChapter[0] + globaldiff)
|
globaldiff = pageid - (aChapter[0] + globaldiff)
|
||||||
buildNCX(path, options.title, chapterlist, chapterNames)
|
buildNCX(path, options.title, chapterlist, chapternames)
|
||||||
buildNAV(path, options.title, chapterlist, chapterNames)
|
buildNAV(path, options.title, chapterlist, chapternames)
|
||||||
buildOPF(path, options.title, filelist, cover)
|
buildOPF(path, options.title, filelist, cover)
|
||||||
|
|
||||||
|
|
||||||
def imgDirectoryProcessing(path):
|
def imgDirectoryProcessing(path):
|
||||||
global workerPool, workerOutput
|
global workerPool, workerOutput
|
||||||
workerPool = Pool()
|
workerPool = Pool(maxtasksperchild=100)
|
||||||
workerOutput = []
|
workerOutput = []
|
||||||
options.imgIndex = {}
|
options.imgMetadata = {}
|
||||||
options.imgPurgeIndex = []
|
options.imgOld = []
|
||||||
work = []
|
work = []
|
||||||
pagenumber = 0
|
pagenumber = 0
|
||||||
for (dirpath, dirnames, filenames) in walk(path):
|
for dirpath, _, filenames in os.walk(path):
|
||||||
for afile in filenames:
|
for afile in filenames:
|
||||||
pagenumber += 1
|
pagenumber += 1
|
||||||
work.append([afile, dirpath, options])
|
work.append([afile, dirpath, options])
|
||||||
@@ -482,9 +526,9 @@ def imgDirectoryProcessing(path):
|
|||||||
if len(workerOutput) > 0:
|
if len(workerOutput) > 0:
|
||||||
rmtree(os.path.join(path, '..', '..'), True)
|
rmtree(os.path.join(path, '..', '..'), True)
|
||||||
raise RuntimeError("One of workers crashed. Cause: " + workerOutput[0][0], workerOutput[0][1])
|
raise RuntimeError("One of workers crashed. Cause: " + workerOutput[0][0], workerOutput[0][1])
|
||||||
for file in options.imgPurgeIndex:
|
for file in options.imgOld:
|
||||||
if os.path.isfile(file):
|
if os.path.isfile(file):
|
||||||
saferRemove(file)
|
os.remove(file)
|
||||||
else:
|
else:
|
||||||
rmtree(os.path.join(path, '..', '..'), True)
|
rmtree(os.path.join(path, '..', '..'), True)
|
||||||
raise UserWarning("Source directory is empty.")
|
raise UserWarning("Source directory is empty.")
|
||||||
@@ -497,8 +541,8 @@ def imgFileProcessingTick(output):
|
|||||||
else:
|
else:
|
||||||
for page in output:
|
for page in output:
|
||||||
if page is not None:
|
if page is not None:
|
||||||
options.imgIndex[page[0]] = page[1]
|
options.imgMetadata[page[0]] = page[1]
|
||||||
options.imgPurgeIndex.append(page[2])
|
options.imgOld.append(page[2])
|
||||||
if GUI:
|
if GUI:
|
||||||
GUI.progressBarTick.emit('tick')
|
GUI.progressBarTick.emit('tick')
|
||||||
if not GUI.conversionAlive:
|
if not GUI.conversionAlive:
|
||||||
@@ -513,7 +557,7 @@ def imgFileProcessing(work):
|
|||||||
output = []
|
output = []
|
||||||
workImg = image.ComicPageParser((dirpath, afile), opt)
|
workImg = image.ComicPageParser((dirpath, afile), opt)
|
||||||
for i in workImg.payload:
|
for i in workImg.payload:
|
||||||
img = image.ComicPage(i[0], i[1], i[2], i[3], i[4], opt)
|
img = image.ComicPage(opt, *i)
|
||||||
if opt.cropping == 2 and not opt.webtoon:
|
if opt.cropping == 2 and not opt.webtoon:
|
||||||
img.cropPageNumber(opt.croppingp)
|
img.cropPageNumber(opt.croppingp)
|
||||||
if opt.cropping > 0 and not opt.webtoon:
|
if opt.cropping > 0 and not opt.webtoon:
|
||||||
@@ -530,6 +574,8 @@ def imgFileProcessing(work):
|
|||||||
|
|
||||||
def getWorkFolder(afile):
|
def getWorkFolder(afile):
|
||||||
if os.path.isdir(afile):
|
if os.path.isdir(afile):
|
||||||
|
if disk_usage(gettempdir())[2] < getDirectorySize(afile) * 2.5:
|
||||||
|
raise UserWarning("Not enough disk space to perform conversion.")
|
||||||
workdir = mkdtemp('', 'KCC-')
|
workdir = mkdtemp('', 'KCC-')
|
||||||
try:
|
try:
|
||||||
os.rmdir(workdir)
|
os.rmdir(workdir)
|
||||||
@@ -537,27 +583,30 @@ def getWorkFolder(afile):
|
|||||||
copytree(afile, fullPath)
|
copytree(afile, fullPath)
|
||||||
sanitizePermissions(fullPath)
|
sanitizePermissions(fullPath)
|
||||||
return workdir
|
return workdir
|
||||||
except:
|
except Exception:
|
||||||
rmtree(workdir, True)
|
rmtree(workdir, True)
|
||||||
raise UserWarning("Failed to prepare a workspace.")
|
raise UserWarning("Failed to prepare a workspace.")
|
||||||
elif os.path.isfile(afile) and afile.lower().endswith('.pdf'):
|
|
||||||
pdf = pdfjpgextract.PdfJpgExtract(afile)
|
|
||||||
path, njpg = pdf.extract()
|
|
||||||
if njpg == 0:
|
|
||||||
rmtree(path, True)
|
|
||||||
raise UserWarning("Failed to extract images from PDF file.")
|
|
||||||
elif os.path.isfile(afile):
|
elif os.path.isfile(afile):
|
||||||
workdir = mkdtemp('', 'KCC-')
|
if disk_usage(gettempdir())[2] < os.path.getsize(afile) * 2.5:
|
||||||
cbx = cbxarchive.CBxArchive(afile)
|
raise UserWarning("Not enough disk space to perform conversion.")
|
||||||
if cbx.isCbxFile():
|
if afile.lower().endswith('.pdf'):
|
||||||
try:
|
pdf = pdfjpgextract.PdfJpgExtract(afile)
|
||||||
path = cbx.extract(workdir)
|
path, njpg = pdf.extract()
|
||||||
except:
|
if njpg == 0:
|
||||||
rmtree(workdir, True)
|
rmtree(path, True)
|
||||||
raise UserWarning("Failed to extract archive.")
|
raise UserWarning("Failed to extract images from PDF file.")
|
||||||
else:
|
else:
|
||||||
rmtree(workdir, True)
|
workdir = mkdtemp('', 'KCC-')
|
||||||
raise UserWarning("Failed to detect archive format.")
|
cbx = cbxarchive.CBxArchive(afile)
|
||||||
|
if cbx.isCbxFile():
|
||||||
|
try:
|
||||||
|
path = cbx.extract(workdir)
|
||||||
|
except Exception:
|
||||||
|
rmtree(workdir, True)
|
||||||
|
raise UserWarning("Failed to extract archive.")
|
||||||
|
else:
|
||||||
|
rmtree(workdir, True)
|
||||||
|
raise UserWarning("Failed to detect archive format.")
|
||||||
else:
|
else:
|
||||||
raise UserWarning("Failed to open source file/directory.")
|
raise UserWarning("Failed to open source file/directory.")
|
||||||
sanitizePermissions(path)
|
sanitizePermissions(path)
|
||||||
@@ -567,7 +616,7 @@ def getWorkFolder(afile):
|
|||||||
return newpath
|
return newpath
|
||||||
|
|
||||||
|
|
||||||
def getOutputFilename(srcpath, wantedname, ext, tomeNumber):
|
def getOutputFilename(srcpath, wantedname, ext, tomenumber):
|
||||||
if srcpath[-1] == os.path.sep:
|
if srcpath[-1] == os.path.sep:
|
||||||
srcpath = srcpath[:-1]
|
srcpath = srcpath[:-1]
|
||||||
if 'Ko' in options.profile and options.format == 'EPUB':
|
if 'Ko' in options.profile and options.format == 'EPUB':
|
||||||
@@ -581,16 +630,16 @@ def getOutputFilename(srcpath, wantedname, ext, tomeNumber):
|
|||||||
filename = os.path.join(os.path.abspath(options.output),
|
filename = os.path.join(os.path.abspath(options.output),
|
||||||
os.path.basename(os.path.splitext(srcpath)[0]) + ext)
|
os.path.basename(os.path.splitext(srcpath)[0]) + ext)
|
||||||
elif os.path.isdir(srcpath):
|
elif os.path.isdir(srcpath):
|
||||||
filename = srcpath + tomeNumber + ext
|
filename = srcpath + tomenumber + ext
|
||||||
else:
|
else:
|
||||||
if 'Ko' in options.profile and options.format == 'EPUB':
|
if 'Ko' in options.profile and options.format == 'EPUB':
|
||||||
path = srcpath.split(os.path.sep)
|
path = srcpath.split(os.path.sep)
|
||||||
path[-1] = ''.join(e for e in path[-1].split('.')[0] if e.isalnum()) + tomeNumber + ext
|
path[-1] = ''.join(e for e in path[-1].split('.')[0] if e.isalnum()) + tomenumber + ext
|
||||||
if not path[-1].split('.')[0]:
|
if not path[-1].split('.')[0]:
|
||||||
path[-1] = 'KCCPlaceholder' + tomeNumber + ext
|
path[-1] = 'KCCPlaceholder' + tomenumber + ext
|
||||||
filename = os.path.sep.join(path)
|
filename = os.path.sep.join(path)
|
||||||
else:
|
else:
|
||||||
filename = os.path.splitext(srcpath)[0] + tomeNumber + ext
|
filename = os.path.splitext(srcpath)[0] + tomenumber + ext
|
||||||
if os.path.isfile(filename):
|
if os.path.isfile(filename):
|
||||||
counter = 0
|
counter = 0
|
||||||
basename = os.path.splitext(filename)[0]
|
basename = os.path.splitext(filename)[0]
|
||||||
@@ -600,7 +649,7 @@ def getOutputFilename(srcpath, wantedname, ext, tomeNumber):
|
|||||||
return filename
|
return filename
|
||||||
|
|
||||||
|
|
||||||
def getComicInfo(path, originalPath):
|
def getComicInfo(path, originalpath):
|
||||||
xmlPath = os.path.join(path, 'ComicInfo.xml')
|
xmlPath = os.path.join(path, 'ComicInfo.xml')
|
||||||
options.authors = ['KCC']
|
options.authors = ['KCC']
|
||||||
options.remoteCovers = {}
|
options.remoteCovers = {}
|
||||||
@@ -609,17 +658,17 @@ def getComicInfo(path, originalPath):
|
|||||||
titleSuffix = ''
|
titleSuffix = ''
|
||||||
if options.title == 'defaulttitle':
|
if options.title == 'defaulttitle':
|
||||||
defaultTitle = True
|
defaultTitle = True
|
||||||
if os.path.isdir(originalPath):
|
if os.path.isdir(originalpath):
|
||||||
options.title = os.path.basename(originalPath)
|
options.title = os.path.basename(originalpath)
|
||||||
else:
|
else:
|
||||||
options.title = os.path.splitext(os.path.basename(originalPath))[0]
|
options.title = os.path.splitext(os.path.basename(originalpath))[0]
|
||||||
else:
|
else:
|
||||||
defaultTitle = False
|
defaultTitle = False
|
||||||
if os.path.exists(xmlPath):
|
if os.path.exists(xmlPath):
|
||||||
try:
|
try:
|
||||||
xml = metadata.MetadataParser(xmlPath)
|
xml = metadata.MetadataParser(xmlPath)
|
||||||
except Exception:
|
except Exception:
|
||||||
saferRemove(xmlPath)
|
os.remove(xmlPath)
|
||||||
return
|
return
|
||||||
options.authors = []
|
options.authors = []
|
||||||
if defaultTitle:
|
if defaultTitle:
|
||||||
@@ -644,13 +693,13 @@ def getComicInfo(path, originalPath):
|
|||||||
options.chapters = xml.data['Bookmarks']
|
options.chapters = xml.data['Bookmarks']
|
||||||
if xml.data['Summary']:
|
if xml.data['Summary']:
|
||||||
options.summary = escape(xml.data['Summary'])
|
options.summary = escape(xml.data['Summary'])
|
||||||
saferRemove(xmlPath)
|
os.remove(xmlPath)
|
||||||
|
|
||||||
|
|
||||||
def getCoversFromMCB(mangaID):
|
def getCoversFromMCB(mangaid):
|
||||||
covers = {}
|
covers = {}
|
||||||
try:
|
try:
|
||||||
jsonRaw = urlopen(Request('http://mcd.iosphe.re/api/v1/series/' + mangaID + '/',
|
jsonRaw = urlopen(Request('http://mcd.iosphe.re/api/v1/series/' + mangaid + '/',
|
||||||
headers={'User-Agent': 'KindleComicConverter/' + __version__}))
|
headers={'User-Agent': 'KindleComicConverter/' + __version__}))
|
||||||
jsonData = loads(jsonRaw.read().decode('utf-8'))
|
jsonData = loads(jsonRaw.read().decode('utf-8'))
|
||||||
for volume in jsonData['Covers']['a']:
|
for volume in jsonData['Covers']['a']:
|
||||||
@@ -663,7 +712,7 @@ def getCoversFromMCB(mangaID):
|
|||||||
|
|
||||||
def getDirectorySize(start_path='.'):
|
def getDirectorySize(start_path='.'):
|
||||||
total_size = 0
|
total_size = 0
|
||||||
for dirpath, dirnames, filenames in walk(start_path):
|
for dirpath, _, filenames in os.walk(start_path):
|
||||||
for f in filenames:
|
for f in filenames:
|
||||||
fp = os.path.join(dirpath, f)
|
fp = os.path.join(dirpath, f)
|
||||||
total_size += os.path.getsize(fp)
|
total_size += os.path.getsize(fp)
|
||||||
@@ -675,9 +724,9 @@ def getTopMargin(deviceres, size):
|
|||||||
return str(round(y, 1))
|
return str(round(y, 1))
|
||||||
|
|
||||||
|
|
||||||
def getPanelViewResolution(imageSize, deviceRes):
|
def getPanelViewResolution(imagesize, deviceres):
|
||||||
scale = float(deviceRes[0]) / float(imageSize[0])
|
scale = float(deviceres[0]) / float(imagesize[0])
|
||||||
return int(deviceRes[0]), int(scale * imageSize[1])
|
return int(deviceres[0]), int(scale * imagesize[1])
|
||||||
|
|
||||||
|
|
||||||
def getPanelViewSize(deviceres, size):
|
def getPanelViewSize(deviceres, size):
|
||||||
@@ -688,33 +737,33 @@ def getPanelViewSize(deviceres, size):
|
|||||||
|
|
||||||
def sanitizeTree(filetree):
|
def sanitizeTree(filetree):
|
||||||
chapterNames = {}
|
chapterNames = {}
|
||||||
for root, dirs, files in walk(filetree, False):
|
for root, dirs, files in os.walk(filetree, False):
|
||||||
for name in files:
|
for name in files:
|
||||||
splitname = os.path.splitext(name)
|
splitname = os.path.splitext(name)
|
||||||
slugified = slugify(splitname[0])
|
slugified = slugify(splitname[0], False)
|
||||||
while os.path.exists(os.path.join(root, slugified + splitname[1])) and splitname[0].upper()\
|
while os.path.exists(os.path.join(root, slugified + splitname[1])) and splitname[0].upper()\
|
||||||
!= slugified.upper():
|
!= slugified.upper():
|
||||||
slugified += "A"
|
slugified += "A"
|
||||||
newKey = os.path.join(root, slugified + splitname[1])
|
newKey = os.path.join(root, slugified + splitname[1])
|
||||||
key = os.path.join(root, name)
|
key = os.path.join(root, name)
|
||||||
if key != newKey:
|
if key != newKey:
|
||||||
saferReplace(key, newKey)
|
os.replace(key, newKey)
|
||||||
for name in dirs:
|
for name in dirs:
|
||||||
tmpName = name
|
tmpName = name
|
||||||
slugified = slugify(name)
|
slugified = slugify(name, True)
|
||||||
while os.path.exists(os.path.join(root, slugified)) and name.upper() != slugified.upper():
|
while os.path.exists(os.path.join(root, slugified)) and name.upper() != slugified.upper():
|
||||||
slugified += "A"
|
slugified += "A"
|
||||||
chapterNames[slugified] = tmpName
|
chapterNames[slugified] = tmpName
|
||||||
newKey = os.path.join(root, slugified)
|
newKey = os.path.join(root, slugified)
|
||||||
key = os.path.join(root, name)
|
key = os.path.join(root, name)
|
||||||
if key != newKey:
|
if key != newKey:
|
||||||
saferReplace(key, newKey)
|
os.replace(key, newKey)
|
||||||
return chapterNames
|
return chapterNames
|
||||||
|
|
||||||
|
|
||||||
def sanitizeTreeKobo(filetree):
|
def sanitizeTreeKobo(filetree):
|
||||||
pageNumber = 0
|
pageNumber = 0
|
||||||
for root, dirs, files in walk(filetree):
|
for root, dirs, files in os.walk(filetree):
|
||||||
dirs, files = walkSort(dirs, files)
|
dirs, files = walkSort(dirs, files)
|
||||||
for name in files:
|
for name in files:
|
||||||
splitname = os.path.splitext(name)
|
splitname = os.path.splitext(name)
|
||||||
@@ -726,11 +775,11 @@ def sanitizeTreeKobo(filetree):
|
|||||||
newKey = os.path.join(root, slugified + splitname[1])
|
newKey = os.path.join(root, slugified + splitname[1])
|
||||||
key = os.path.join(root, name)
|
key = os.path.join(root, name)
|
||||||
if key != newKey:
|
if key != newKey:
|
||||||
saferReplace(key, newKey)
|
os.replace(key, newKey)
|
||||||
|
|
||||||
|
|
||||||
def sanitizePermissions(filetree):
|
def sanitizePermissions(filetree):
|
||||||
for root, dirs, files in walk(filetree, False):
|
for root, dirs, files in os.walk(filetree, False):
|
||||||
for name in files:
|
for name in files:
|
||||||
os.chmod(os.path.join(root, name), S_IWRITE | S_IREAD)
|
os.chmod(os.path.join(root, name), S_IWRITE | S_IREAD)
|
||||||
for name in dirs:
|
for name in dirs:
|
||||||
@@ -785,7 +834,7 @@ def splitProcess(path, mode):
|
|||||||
move(os.path.join(root, name), os.path.join(currentTarget, name))
|
move(os.path.join(root, name), os.path.join(currentTarget, name))
|
||||||
else:
|
else:
|
||||||
firstTome = True
|
firstTome = True
|
||||||
for root, dirs, files in walkLevel(path, 0):
|
for root, dirs, _ in walkLevel(path, 0):
|
||||||
for name in dirs:
|
for name in dirs:
|
||||||
if not firstTome:
|
if not firstTome:
|
||||||
currentTarget, pathRoot = createNewTome()
|
currentTarget, pathRoot = createNewTome()
|
||||||
@@ -796,16 +845,19 @@ def splitProcess(path, mode):
|
|||||||
return output
|
return output
|
||||||
|
|
||||||
|
|
||||||
def detectCorruption(tmpPath, orgPath):
|
def detectCorruption(tmppath, orgpath):
|
||||||
imageNumber = 0
|
imageNumber = 0
|
||||||
imageSmaller = 0
|
imageSmaller = 0
|
||||||
for root, dirs, files in walk(tmpPath, False):
|
alreadyProcessed = False
|
||||||
|
for root, _, files in os.walk(tmppath, False):
|
||||||
for name in files:
|
for name in files:
|
||||||
if getImageFileName(name) is not None:
|
if getImageFileName(name) is not None:
|
||||||
|
if not alreadyProcessed and getImageFileName(name)[0].endswith('-kcc'):
|
||||||
|
alreadyProcessed = True
|
||||||
path = os.path.join(root, name)
|
path = os.path.join(root, name)
|
||||||
pathOrg = orgPath + path.split('OEBPS' + os.path.sep + 'Images')[1]
|
pathOrg = orgpath + path.split('OEBPS' + os.path.sep + 'Images')[1]
|
||||||
if os.path.getsize(path) == 0:
|
if os.path.getsize(path) == 0:
|
||||||
rmtree(os.path.join(tmpPath, '..', '..'), True)
|
rmtree(os.path.join(tmppath, '..', '..'), True)
|
||||||
raise RuntimeError('Image file %s is corrupted.' % pathOrg)
|
raise RuntimeError('Image file %s is corrupted.' % pathOrg)
|
||||||
try:
|
try:
|
||||||
img = Image.open(path)
|
img = Image.open(path)
|
||||||
@@ -816,13 +868,19 @@ def detectCorruption(tmpPath, orgPath):
|
|||||||
if options.profileData[1][0] > img.size[0] and options.profileData[1][1] > img.size[1]:
|
if options.profileData[1][0] > img.size[0] and options.profileData[1][1] > img.size[1]:
|
||||||
imageSmaller += 1
|
imageSmaller += 1
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
rmtree(os.path.join(tmpPath, '..', '..'), True)
|
rmtree(os.path.join(tmppath, '..', '..'), True)
|
||||||
if 'decoder' in str(err) and 'not available' in str(err):
|
if 'decoder' in str(err) and 'not available' in str(err):
|
||||||
raise RuntimeError('Pillow was compiled without JPG and/or PNG decoder.')
|
raise RuntimeError('Pillow was compiled without JPG and/or PNG decoder.')
|
||||||
else:
|
else:
|
||||||
raise RuntimeError('Image file %s is corrupted.' % pathOrg)
|
raise RuntimeError('Image file %s is corrupted.' % pathOrg)
|
||||||
else:
|
else:
|
||||||
saferRemove(os.path.join(root, name))
|
os.remove(os.path.join(root, name))
|
||||||
|
if alreadyProcessed:
|
||||||
|
print("WARNING: Source files are probably created by KCC. The second conversion will decrease quality.")
|
||||||
|
if GUI:
|
||||||
|
GUI.addMessage.emit('Source files are probably created by KCC. The second conversion will decrease quality.'
|
||||||
|
, 'warning', False)
|
||||||
|
GUI.addMessage.emit('', '', False)
|
||||||
if imageSmaller > imageNumber * 0.25 and not options.upscale and not options.stretch:
|
if imageSmaller > imageNumber * 0.25 and not options.upscale and not options.stretch:
|
||||||
print("WARNING: More than 25% of images are smaller than target device resolution. "
|
print("WARNING: More than 25% of images are smaller than target device resolution. "
|
||||||
"Consider enabling stretching or upscaling to improve readability.")
|
"Consider enabling stretching or upscaling to improve readability.")
|
||||||
@@ -839,25 +897,28 @@ def createNewTome():
|
|||||||
return tomePath, tomePathRoot
|
return tomePath, tomePathRoot
|
||||||
|
|
||||||
|
|
||||||
def slugify(value):
|
def slugify(value, isdir):
|
||||||
value = slugifyExt(value)
|
if isdir:
|
||||||
|
value = slugifyExt(value, regex_pattern=r'[^-a-z0-9_\.]+').strip('.')
|
||||||
|
else:
|
||||||
|
value = slugifyExt(value).strip('.')
|
||||||
value = sub(r'0*([0-9]{4,})', r'\1', sub(r'([0-9]+)', r'0000\1', value, count=2))
|
value = sub(r'0*([0-9]{4,})', r'\1', sub(r'([0-9]+)', r'0000\1', value, count=2))
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
def makeZIP(zipFilename, baseDir, isEPUB=False):
|
def makeZIP(zipfilename, basedir, isepub=False):
|
||||||
zipFilename = os.path.abspath(zipFilename) + '.zip'
|
zipfilename = os.path.abspath(zipfilename) + '.zip'
|
||||||
zipOutput = ZipFile(zipFilename, 'w', ZIP_DEFLATED)
|
zipOutput = ZipFile(zipfilename, 'w', ZIP_DEFLATED)
|
||||||
if isEPUB:
|
if isepub:
|
||||||
zipOutput.writestr('mimetype', 'application/epub+zip', ZIP_STORED)
|
zipOutput.writestr('mimetype', 'application/epub+zip', ZIP_STORED)
|
||||||
for dirpath, dirnames, filenames in walk(baseDir):
|
for dirpath, _, filenames in os.walk(basedir):
|
||||||
for name in filenames:
|
for name in filenames:
|
||||||
path = os.path.normpath(os.path.join(dirpath, name))
|
path = os.path.normpath(os.path.join(dirpath, name))
|
||||||
aPath = os.path.normpath(os.path.join(dirpath.replace(baseDir, ''), name))
|
aPath = os.path.normpath(os.path.join(dirpath.replace(basedir, ''), name))
|
||||||
if os.path.isfile(path):
|
if os.path.isfile(path):
|
||||||
zipOutput.write(path, aPath)
|
zipOutput.write(path, aPath)
|
||||||
zipOutput.close()
|
zipOutput.close()
|
||||||
return zipFilename
|
return zipfilename
|
||||||
|
|
||||||
|
|
||||||
def makeParser():
|
def makeParser():
|
||||||
@@ -870,10 +931,12 @@ def makeParser():
|
|||||||
otherOptions = OptionGroup(psr, "OTHER")
|
otherOptions = OptionGroup(psr, "OTHER")
|
||||||
|
|
||||||
mainOptions.add_option("-p", "--profile", action="store", dest="profile", default="KV",
|
mainOptions.add_option("-p", "--profile", action="store", dest="profile", default="KV",
|
||||||
help="Device profile (Available options: K1, K2, K3, K45, KDX, KPW, KV, KoMT, KoG, KoGHD,"
|
help="Device profile (Available options: K1, K2, K34, K578, KDX, KPW, KV, KO, KoMT, KoG,"
|
||||||
" KoA, KoAHD, KoAH2O, KoAO) [Default=KV]")
|
" KoGHD, KoA, KoAHD, KoAH2O, KoAO) [Default=KV]")
|
||||||
mainOptions.add_option("-m", "--manga-style", action="store_true", dest="righttoleft", default=False,
|
mainOptions.add_option("-m", "--manga-style", action="store_true", dest="righttoleft", default=False,
|
||||||
help="Manga style (right-to-left reading and splitting)")
|
help="Manga style (right-to-left reading and splitting)")
|
||||||
|
mainOptions.add_option("-q", "--hq", action="store_true", dest="hq", default=False,
|
||||||
|
help="Try to increase the quality of magnification")
|
||||||
mainOptions.add_option("-2", "--two-panel", action="store_true", dest="autoscale", default=False,
|
mainOptions.add_option("-2", "--two-panel", action="store_true", dest="autoscale", default=False,
|
||||||
help="Display two not four panels in Panel View mode")
|
help="Display two not four panels in Panel View mode")
|
||||||
mainOptions.add_option("-w", "--webtoon", action="store_true", dest="webtoon", default=False,
|
mainOptions.add_option("-w", "--webtoon", action="store_true", dest="webtoon", default=False,
|
||||||
@@ -884,7 +947,7 @@ def makeParser():
|
|||||||
outputOptions.add_option("-t", "--title", action="store", dest="title", default="defaulttitle",
|
outputOptions.add_option("-t", "--title", action="store", dest="title", default="defaulttitle",
|
||||||
help="Comic title [Default=filename or directory name]")
|
help="Comic title [Default=filename or directory name]")
|
||||||
outputOptions.add_option("-f", "--format", action="store", dest="format", default="Auto",
|
outputOptions.add_option("-f", "--format", action="store", dest="format", default="Auto",
|
||||||
help="Output format (Available options: Auto, MOBI, EPUB, CBZ) [Default=Auto]")
|
help="Output format (Available options: Auto, MOBI, EPUB, CBZ, KFX) [Default=Auto]")
|
||||||
outputOptions.add_option("-b", "--batchsplit", type="int", dest="batchsplit", default="0",
|
outputOptions.add_option("-b", "--batchsplit", type="int", dest="batchsplit", default="0",
|
||||||
help="Split output into multiple files. 0: Don't split 1: Automatic mode "
|
help="Split output into multiple files. 0: Don't split 1: Automatic mode "
|
||||||
"2: Consider every subdirectory as separate volume [Default=0]")
|
"2: Consider every subdirectory as separate volume [Default=0]")
|
||||||
@@ -931,38 +994,48 @@ def checkOptions():
|
|||||||
options.panelview = True
|
options.panelview = True
|
||||||
options.iskindle = False
|
options.iskindle = False
|
||||||
options.bordersColor = None
|
options.bordersColor = None
|
||||||
|
options.kfx = False
|
||||||
if options.format == 'Auto':
|
if options.format == 'Auto':
|
||||||
if options.profile in ['K1', 'K2', 'K3', 'K45', 'KPW', 'KV']:
|
if options.profile in ['K1', 'K2', 'K34', 'K578', 'KPW', 'KV', 'KO']:
|
||||||
options.format = 'MOBI'
|
options.format = 'MOBI'
|
||||||
elif options.profile in ['OTHER', 'KoMT', 'KoG', 'KoGHD', 'KoA', 'KoAHD', 'KoAH2O', 'KoAO']:
|
elif options.profile in ['OTHER', 'KoMT', 'KoG', 'KoGHD', 'KoA', 'KoAHD', 'KoAH2O', 'KoAO']:
|
||||||
options.format = 'EPUB'
|
options.format = 'EPUB'
|
||||||
elif options.profile in ['KDX']:
|
elif options.profile in ['KDX']:
|
||||||
options.format = 'CBZ'
|
options.format = 'CBZ'
|
||||||
if options.profile in ['K1', 'K2', 'K3', 'K45', 'KPW', 'KV']:
|
if options.profile in ['K1', 'K2', 'K34', 'K578', 'KPW', 'KV', 'KO']:
|
||||||
options.iskindle = True
|
options.iskindle = True
|
||||||
if options.white_borders:
|
if options.white_borders:
|
||||||
options.bordersColor = 'white'
|
options.bordersColor = 'white'
|
||||||
if options.black_borders:
|
if options.black_borders:
|
||||||
options.bordersColor = 'black'
|
options.bordersColor = 'black'
|
||||||
# Splitting MOBI is not optional
|
# Splitting MOBI is not optional
|
||||||
if options.format == 'MOBI' and options.batchsplit != 2:
|
if (options.format == 'MOBI' or options.format == 'KFX') and options.batchsplit != 2:
|
||||||
options.batchsplit = 1
|
options.batchsplit = 1
|
||||||
# Older Kindle models don't support Panel View.
|
# Older Kindle models don't support Panel View.
|
||||||
if options.profile == 'K1' or options.profile == 'K2' or options.profile == 'KDX':
|
if options.profile == 'K1' or options.profile == 'K2' or options.profile == 'K34' or options.profile == 'KDX':
|
||||||
options.panelview = False
|
options.panelview = False
|
||||||
|
options.hq = False
|
||||||
# Webtoon mode mandatory options
|
# Webtoon mode mandatory options
|
||||||
if options.webtoon:
|
if options.webtoon:
|
||||||
options.panelview = False
|
options.panelview = False
|
||||||
options.righttoleft = False
|
options.righttoleft = False
|
||||||
options.upscale = True
|
options.upscale = True
|
||||||
|
options.hq = False
|
||||||
# Disable all Kindle features for other e-readers
|
# Disable all Kindle features for other e-readers
|
||||||
if options.profile == 'OTHER':
|
if options.profile == 'OTHER':
|
||||||
options.panelview = False
|
options.panelview = False
|
||||||
|
options.hq = False
|
||||||
if 'Ko' in options.profile:
|
if 'Ko' in options.profile:
|
||||||
options.panelview = False
|
options.panelview = False
|
||||||
|
options.hq = False
|
||||||
# CBZ files on Kindle DX/DXG support higher resolution
|
# CBZ files on Kindle DX/DXG support higher resolution
|
||||||
if options.profile == 'KDX' and options.format == 'CBZ':
|
if options.profile == 'KDX' and options.format == 'CBZ':
|
||||||
options.customheight = 1200
|
options.customheight = 1200
|
||||||
|
# KFX output create EPUB that might be can be by jhowell KFX Output Calibre plugin
|
||||||
|
if options.format == 'KFX':
|
||||||
|
options.format = 'EPUB'
|
||||||
|
options.kfx = True
|
||||||
|
options.panelview = False
|
||||||
# Override profile data
|
# Override profile data
|
||||||
if options.customwidth != 0 or options.customheight != 0:
|
if options.customwidth != 0 or options.customheight != 0:
|
||||||
X = image.ProfileData.Profiles[options.profile][1][0]
|
X = image.ProfileData.Profiles[options.profile][1][0]
|
||||||
@@ -1013,13 +1086,13 @@ def checkPre(source):
|
|||||||
try:
|
try:
|
||||||
with TemporaryFile(prefix='KCC-', dir=src):
|
with TemporaryFile(prefix='KCC-', dir=src):
|
||||||
pass
|
pass
|
||||||
except:
|
except Exception:
|
||||||
raise UserWarning("Target directory is not writable.")
|
raise UserWarning("Target directory is not writable.")
|
||||||
|
|
||||||
|
|
||||||
def makeBook(source, qtGUI=None):
|
def makeBook(source, qtgui=None):
|
||||||
global GUI
|
global GUI
|
||||||
GUI = qtGUI
|
GUI = qtgui
|
||||||
if GUI:
|
if GUI:
|
||||||
GUI.progressBarTick.emit('1')
|
GUI.progressBarTick.emit('1')
|
||||||
else:
|
else:
|
||||||
@@ -1035,7 +1108,7 @@ def makeBook(source, qtGUI=None):
|
|||||||
y = 1024
|
y = 1024
|
||||||
else:
|
else:
|
||||||
y = image.ProfileData.Profiles[options.profile][1][1]
|
y = image.ProfileData.Profiles[options.profile][1][1]
|
||||||
comic2panel.main(['-y ' + str(y), '-i', '-m', path], qtGUI)
|
comic2panel.main(['-y ' + str(y), '-i', '-m', path], qtgui)
|
||||||
print("Processing images...")
|
print("Processing images...")
|
||||||
if GUI:
|
if GUI:
|
||||||
GUI.progressBarTick.emit('Processing images')
|
GUI.progressBarTick.emit('Processing images')
|
||||||
@@ -1107,14 +1180,14 @@ def makeBook(source, qtGUI=None):
|
|||||||
print('Error: Failed to tweak KindleGen output!')
|
print('Error: Failed to tweak KindleGen output!')
|
||||||
return filepath
|
return filepath
|
||||||
else:
|
else:
|
||||||
saferRemove(i.replace('.epub', '.mobi') + '_toclean')
|
os.remove(i.replace('.epub', '.mobi') + '_toclean')
|
||||||
if k.path and k.coverSupport:
|
if k.path and k.coverSupport:
|
||||||
options.covers[filepath.index(i)][0].saveToKindle(k, options.covers[filepath.index(i)][1])
|
options.covers[filepath.index(i)][0].saveToKindle(k, options.covers[filepath.index(i)][1])
|
||||||
return filepath
|
return filepath
|
||||||
|
|
||||||
|
|
||||||
def makeMOBIFix(item, uuid):
|
def makeMOBIFix(item, uuid):
|
||||||
saferRemove(item)
|
os.remove(item)
|
||||||
mobiPath = item.replace('.epub', '.mobi')
|
mobiPath = item.replace('.epub', '.mobi')
|
||||||
move(mobiPath, mobiPath + '_toclean')
|
move(mobiPath, mobiPath + '_toclean')
|
||||||
try:
|
try:
|
||||||
@@ -1166,18 +1239,20 @@ def makeMOBIWorker(item):
|
|||||||
return [kindlegenErrorCode, kindlegenError, item]
|
return [kindlegenErrorCode, kindlegenError, item]
|
||||||
|
|
||||||
|
|
||||||
def makeMOBI(work, qtGUI=None):
|
def makeMOBI(work, qtgui=None):
|
||||||
global GUI, makeMOBIWorkerPool, makeMOBIWorkerOutput
|
global GUI, makeMOBIWorkerPool, makeMOBIWorkerOutput
|
||||||
GUI = qtGUI
|
GUI = qtgui
|
||||||
makeMOBIWorkerOutput = []
|
makeMOBIWorkerOutput = []
|
||||||
availableMemory = virtual_memory().total / 1000000000
|
availableMemory = virtual_memory().total / 1000000000
|
||||||
if availableMemory <= 2:
|
if availableMemory <= 2:
|
||||||
threadNumber = 1
|
threadNumber = 1
|
||||||
elif 2 < availableMemory <= 4:
|
elif 2 < availableMemory <= 4:
|
||||||
threadNumber = 2
|
threadNumber = 2
|
||||||
else:
|
elif 4 < availableMemory <= 8:
|
||||||
threadNumber = 4
|
threadNumber = 4
|
||||||
makeMOBIWorkerPool = Pool(threadNumber)
|
else:
|
||||||
|
threadNumber = None
|
||||||
|
makeMOBIWorkerPool = Pool(threadNumber, maxtasksperchild=10)
|
||||||
for i in work:
|
for i in work:
|
||||||
makeMOBIWorkerPool.apply_async(func=makeMOBIWorker, args=(i, ), callback=makeMOBIWorkerTick)
|
makeMOBIWorkerPool.apply_async(func=makeMOBIWorker, args=(i, ), callback=makeMOBIWorkerTick)
|
||||||
makeMOBIWorkerPool.close()
|
makeMOBIWorkerPool.close()
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
||||||
# Copyright (c) 2013-2017 Pawel Jastrzebski <pawelj@iosphe.re>
|
# Copyright (c) 2013-2018 Pawel Jastrzebski <pawelj@iosphe.re>
|
||||||
#
|
#
|
||||||
# Permission to use, copy, modify, and/or distribute this software for
|
# Permission to use, copy, modify, and/or distribute this software for
|
||||||
# any purpose with or without fee is hereby granted, provided that the
|
# any purpose with or without fee is hereby granted, provided that the
|
||||||
@@ -23,16 +23,12 @@ import sys
|
|||||||
from shutil import rmtree, copytree, move
|
from shutil import rmtree, copytree, move
|
||||||
from optparse import OptionParser, OptionGroup
|
from optparse import OptionParser, OptionGroup
|
||||||
from multiprocessing import Pool
|
from multiprocessing import Pool
|
||||||
from PIL import Image, ImageStat, ImageOps
|
from PIL import Image, ImageChops, ImageOps, ImageDraw
|
||||||
from .shared import getImageFileName, walkLevel, walkSort, saferRemove, sanitizeTrace
|
from .shared import getImageFileName, walkLevel, walkSort, sanitizeTrace
|
||||||
try:
|
try:
|
||||||
from PyQt5 import QtCore
|
from PyQt5 import QtCore
|
||||||
except ImportError:
|
except ImportError:
|
||||||
QtCore = None
|
QtCore = None
|
||||||
try:
|
|
||||||
from scandir import walk
|
|
||||||
except ImportError:
|
|
||||||
walk = os.walk
|
|
||||||
|
|
||||||
|
|
||||||
def mergeDirectoryTick(output):
|
def mergeDirectoryTick(output):
|
||||||
@@ -52,7 +48,7 @@ def mergeDirectory(work):
|
|||||||
imagesValid = []
|
imagesValid = []
|
||||||
sizes = []
|
sizes = []
|
||||||
targetHeight = 0
|
targetHeight = 0
|
||||||
for root, dirs, files in walkLevel(directory, 0):
|
for root, _, files in walkLevel(directory, 0):
|
||||||
for name in files:
|
for name in files:
|
||||||
if getImageFileName(name) is not None:
|
if getImageFileName(name) is not None:
|
||||||
i = Image.open(os.path.join(root, name))
|
i = Image.open(os.path.join(root, name))
|
||||||
@@ -71,43 +67,20 @@ def mergeDirectory(work):
|
|||||||
result = Image.new('RGB', (targetWidth, targetHeight))
|
result = Image.new('RGB', (targetWidth, targetHeight))
|
||||||
y = 0
|
y = 0
|
||||||
for i in imagesValid:
|
for i in imagesValid:
|
||||||
img = Image.open(i)
|
img = Image.open(i).convert('RGB')
|
||||||
img = img.convert('RGB')
|
|
||||||
if img.size[0] < targetWidth:
|
if img.size[0] < targetWidth:
|
||||||
img = ImageOps.fit(img, (targetWidth, img.size[1]), method=Image.BICUBIC, centering=(0.5, 0.5))
|
img = ImageOps.fit(img, (targetWidth, img.size[1]), method=Image.BICUBIC, centering=(0.5, 0.5))
|
||||||
result.paste(img, (0, y))
|
result.paste(img, (0, y))
|
||||||
y += img.size[1]
|
y += img.size[1]
|
||||||
saferRemove(i)
|
os.remove(i)
|
||||||
savePath = os.path.split(imagesValid[0])
|
savePath = os.path.split(imagesValid[0])
|
||||||
result.save(os.path.join(savePath[0], os.path.splitext(savePath[1])[0] + '.png'), 'PNG')
|
result.save(os.path.join(savePath[0], os.path.splitext(savePath[1])[0] + '.png'), 'PNG')
|
||||||
except Exception:
|
except Exception:
|
||||||
return str(sys.exc_info()[1]), sanitizeTrace(sys.exc_info()[2])
|
return str(sys.exc_info()[1]), sanitizeTrace(sys.exc_info()[2])
|
||||||
|
|
||||||
|
|
||||||
def sanitizePanelSize(panel, opt):
|
def detectSolid(img):
|
||||||
newPanels = []
|
return not ImageChops.invert(img).getbbox() or not img.getbbox()
|
||||||
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])
|
|
||||||
newPanels.append([panel[1] - diff * 6, panel[1] - diff * 5, diff])
|
|
||||||
newPanels.append([panel[1] - diff * 5, panel[1] - diff * 4, diff])
|
|
||||||
newPanels.append([panel[1] - diff * 4, 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] > 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] > 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:
|
|
||||||
newPanels = [panel]
|
|
||||||
return newPanels
|
|
||||||
|
|
||||||
|
|
||||||
def splitImageTick(output):
|
def splitImageTick(output):
|
||||||
@@ -120,61 +93,64 @@ def splitImageTick(output):
|
|||||||
splitWorkerPool.terminate()
|
splitWorkerPool.terminate()
|
||||||
|
|
||||||
|
|
||||||
|
# noinspection PyUnboundLocalVariable
|
||||||
def splitImage(work):
|
def splitImage(work):
|
||||||
try:
|
try:
|
||||||
path = work[0]
|
path = work[0]
|
||||||
name = work[1]
|
name = work[1]
|
||||||
opt = work[2]
|
opt = work[2]
|
||||||
# Hardcoded options
|
|
||||||
threshold = 1.0
|
|
||||||
delta = 15
|
|
||||||
fileExpanded = os.path.splitext(name)
|
|
||||||
filePath = os.path.join(path, name)
|
filePath = os.path.join(path, name)
|
||||||
image = Image.open(filePath)
|
imgOrg = Image.open(filePath).convert('RGB')
|
||||||
image = image.convert('RGB')
|
imgProcess = Image.open(filePath).convert('1')
|
||||||
widthImg, heightImg = image.size
|
widthImg, heightImg = imgOrg.size
|
||||||
if heightImg > opt.height:
|
if heightImg > opt.height:
|
||||||
if opt.debug:
|
if opt.debug:
|
||||||
from PIL import ImageDraw
|
drawImg = Image.open(filePath).convert(mode='RGBA')
|
||||||
debugImage = Image.open(filePath)
|
draw = ImageDraw.Draw(drawImg)
|
||||||
draw = ImageDraw.Draw(debugImage)
|
|
||||||
|
|
||||||
# Find panels
|
# Find panels
|
||||||
y1 = 0
|
yWork = 0
|
||||||
y2 = 15
|
panelDetected = False
|
||||||
panels = []
|
panels = []
|
||||||
while y2 < heightImg:
|
while yWork < heightImg:
|
||||||
while ImageStat.Stat(image.crop([0, y1, widthImg, y2])).var[0] < threshold and y2 < heightImg:
|
tmpImg = imgProcess.crop([0, yWork, widthImg, yWork + 4])
|
||||||
y2 += delta
|
solid = detectSolid(tmpImg)
|
||||||
y2 -= delta
|
if not solid and not panelDetected:
|
||||||
y1Temp = y2
|
panelDetected = True
|
||||||
y1 = y2 + delta
|
panelY1 = yWork - 2
|
||||||
y2 = y1 + delta
|
if solid and panelDetected:
|
||||||
while ImageStat.Stat(image.crop([0, y1, widthImg, y2])).var[0] >= threshold and y2 < heightImg:
|
panelDetected = False
|
||||||
y1 += delta
|
panelY2 = yWork + 6
|
||||||
y2 += delta
|
panels.append((panelY1, panelY2, panelY2 - panelY1))
|
||||||
if y1 + delta >= heightImg:
|
yWork += 5
|
||||||
y1 = heightImg - 1
|
|
||||||
y2Temp = y1
|
# Split too big panels
|
||||||
if opt.debug:
|
panelsProcessed = []
|
||||||
draw.line([(0, y1Temp), (widthImg, y1Temp)], fill=(0, 255, 0))
|
for panel in panels:
|
||||||
draw.line([(0, y2Temp), (widthImg, y2Temp)], fill=(255, 0, 0))
|
if panel[2] <= opt.height * 1.5:
|
||||||
panelHeight = y2Temp - y1Temp
|
panelsProcessed.append(panel)
|
||||||
if panelHeight > delta:
|
elif panel[2] < opt.height * 2:
|
||||||
# Panels that can't be cut nicely will be forcefully splitted
|
diff = panel[2] - opt.height
|
||||||
panelsCleaned = sanitizePanelSize([y1Temp, y2Temp, panelHeight], opt)
|
panelsProcessed.append((panel[0], panel[1] - diff, opt.height))
|
||||||
for panel in panelsCleaned:
|
panelsProcessed.append((panel[1] - opt.height, panel[1], opt.height))
|
||||||
panels.append(panel)
|
else:
|
||||||
|
parts = round(panel[2] / opt.height)
|
||||||
|
diff = panel[2] // parts
|
||||||
|
for x in range(0, parts):
|
||||||
|
panelsProcessed.append((panel[0] + (x * diff), panel[1] - ((parts - x - 1) * diff), diff))
|
||||||
|
|
||||||
if opt.debug:
|
if opt.debug:
|
||||||
# noinspection PyUnboundLocalVariable
|
for panel in panelsProcessed:
|
||||||
debugImage.save(os.path.join(path, fileExpanded[0] + '-debug.png'), 'PNG')
|
draw.rectangle([(0, panel[0]), (widthImg, panel[1])], (0, 255, 0, 128), (0, 0, 255, 255))
|
||||||
|
debugImage = Image.alpha_composite(imgOrg.convert(mode='RGBA'), drawImg)
|
||||||
|
debugImage.save(os.path.join(path, os.path.splitext(name)[0] + '-debug.png'), 'PNG')
|
||||||
|
|
||||||
# Create virtual pages
|
# Create virtual pages
|
||||||
pages = []
|
pages = []
|
||||||
currentPage = []
|
currentPage = []
|
||||||
pageLeft = opt.height
|
pageLeft = opt.height
|
||||||
panelNumber = 0
|
panelNumber = 0
|
||||||
for panel in panels:
|
for panel in panelsProcessed:
|
||||||
if pageLeft - panel[2] > 0:
|
if pageLeft - panel[2] > 0:
|
||||||
pageLeft -= panel[2]
|
pageLeft -= panel[2]
|
||||||
currentPage.append(panelNumber)
|
currentPage.append(panelNumber)
|
||||||
@@ -194,21 +170,21 @@ def splitImage(work):
|
|||||||
pageHeight = 0
|
pageHeight = 0
|
||||||
targetHeight = 0
|
targetHeight = 0
|
||||||
for panel in page:
|
for panel in page:
|
||||||
pageHeight += panels[panel][2]
|
pageHeight += panelsProcessed[panel][2]
|
||||||
if pageHeight > delta:
|
if pageHeight > 15:
|
||||||
newPage = Image.new('RGB', (widthImg, pageHeight))
|
newPage = Image.new('RGB', (widthImg, pageHeight))
|
||||||
for panel in page:
|
for panel in page:
|
||||||
panelImg = image.crop([0, panels[panel][0], widthImg, panels[panel][1]])
|
panelImg = imgOrg.crop([0, panelsProcessed[panel][0], widthImg, panelsProcessed[panel][1]])
|
||||||
newPage.paste(panelImg, (0, targetHeight))
|
newPage.paste(panelImg, (0, targetHeight))
|
||||||
targetHeight += panels[panel][2]
|
targetHeight += panelsProcessed[panel][2]
|
||||||
newPage.save(os.path.join(path, fileExpanded[0] + '-' + str(pageNumber) + '.png'), 'PNG')
|
newPage.save(os.path.join(path, os.path.splitext(name)[0] + '-' + str(pageNumber) + '.png'), 'PNG')
|
||||||
pageNumber += 1
|
pageNumber += 1
|
||||||
saferRemove(filePath)
|
os.remove(filePath)
|
||||||
except Exception:
|
except Exception:
|
||||||
return str(sys.exc_info()[1]), sanitizeTrace(sys.exc_info()[2])
|
return str(sys.exc_info()[1]), sanitizeTrace(sys.exc_info()[2])
|
||||||
|
|
||||||
|
|
||||||
def main(argv=None, qtGUI=None):
|
def main(argv=None, qtgui=None):
|
||||||
global options, GUI, splitWorkerPool, splitWorkerOutput, mergeWorkerPool, mergeWorkerOutput
|
global options, GUI, splitWorkerPool, splitWorkerOutput, mergeWorkerPool, mergeWorkerOutput
|
||||||
parser = OptionParser(usage="Usage: kcc-c2p [options] comic_folder", add_help_option=False)
|
parser = OptionParser(usage="Usage: kcc-c2p [options] comic_folder", add_help_option=False)
|
||||||
mainOptions = OptionGroup(parser, "MANDATORY")
|
mainOptions = OptionGroup(parser, "MANDATORY")
|
||||||
@@ -220,14 +196,14 @@ def main(argv=None, qtGUI=None):
|
|||||||
mainOptions.add_option("-m", "--merge", action="store_true", dest="merge", default=False,
|
mainOptions.add_option("-m", "--merge", action="store_true", dest="merge", default=False,
|
||||||
help="Combine every directory into a single image before splitting")
|
help="Combine every directory into a single image before splitting")
|
||||||
otherOptions.add_option("-d", "--debug", action="store_true", dest="debug", default=False,
|
otherOptions.add_option("-d", "--debug", action="store_true", dest="debug", default=False,
|
||||||
help="Create debug file for every splitted image")
|
help="Create debug file for every split image")
|
||||||
otherOptions.add_option("-h", "--help", action="help",
|
otherOptions.add_option("-h", "--help", action="help",
|
||||||
help="Show this help message and exit")
|
help="Show this help message and exit")
|
||||||
parser.add_option_group(mainOptions)
|
parser.add_option_group(mainOptions)
|
||||||
parser.add_option_group(otherOptions)
|
parser.add_option_group(otherOptions)
|
||||||
options, args = parser.parse_args(argv)
|
options, args = parser.parse_args(argv)
|
||||||
if qtGUI:
|
if qtgui:
|
||||||
GUI = qtGUI
|
GUI = qtgui
|
||||||
else:
|
else:
|
||||||
GUI = None
|
GUI = None
|
||||||
if len(args) != 1:
|
if len(args) != 1:
|
||||||
@@ -242,15 +218,15 @@ def main(argv=None, qtGUI=None):
|
|||||||
work = []
|
work = []
|
||||||
pagenumber = 1
|
pagenumber = 1
|
||||||
splitWorkerOutput = []
|
splitWorkerOutput = []
|
||||||
splitWorkerPool = Pool()
|
splitWorkerPool = Pool(maxtasksperchild=10)
|
||||||
if options.merge:
|
if options.merge:
|
||||||
print("Merging images...")
|
print("Merging images...")
|
||||||
directoryNumer = 1
|
directoryNumer = 1
|
||||||
mergeWork = []
|
mergeWork = []
|
||||||
mergeWorkerOutput = []
|
mergeWorkerOutput = []
|
||||||
mergeWorkerPool = Pool()
|
mergeWorkerPool = Pool(maxtasksperchild=10)
|
||||||
mergeWork.append([options.targetDir])
|
mergeWork.append([options.targetDir])
|
||||||
for root, dirs, files in walk(options.targetDir, False):
|
for root, dirs, files in os.walk(options.targetDir, False):
|
||||||
dirs, files = walkSort(dirs, files)
|
dirs, files = walkSort(dirs, files)
|
||||||
for directory in dirs:
|
for directory in dirs:
|
||||||
directoryNumer += 1
|
directoryNumer += 1
|
||||||
@@ -267,15 +243,16 @@ def main(argv=None, qtGUI=None):
|
|||||||
raise UserWarning("Conversion interrupted.")
|
raise UserWarning("Conversion interrupted.")
|
||||||
if len(mergeWorkerOutput) > 0:
|
if len(mergeWorkerOutput) > 0:
|
||||||
rmtree(options.targetDir, True)
|
rmtree(options.targetDir, True)
|
||||||
raise RuntimeError("One of workers crashed. Cause: " + mergeWorkerOutput[0][0], mergeWorkerOutput[0][1])
|
raise RuntimeError("One of workers crashed. Cause: " + mergeWorkerOutput[0][0],
|
||||||
|
mergeWorkerOutput[0][1])
|
||||||
print("Splitting images...")
|
print("Splitting images...")
|
||||||
for root, dirs, files in walk(options.targetDir, False):
|
for root, _, files in os.walk(options.targetDir, False):
|
||||||
for name in files:
|
for name in files:
|
||||||
if getImageFileName(name) is not None:
|
if getImageFileName(name) is not None:
|
||||||
pagenumber += 1
|
pagenumber += 1
|
||||||
work.append([root, name, options])
|
work.append([root, name, options])
|
||||||
else:
|
else:
|
||||||
saferRemove(os.path.join(root, name))
|
os.remove(os.path.join(root, name))
|
||||||
if GUI:
|
if GUI:
|
||||||
GUI.progressBarTick.emit('Splitting images')
|
GUI.progressBarTick.emit('Splitting images')
|
||||||
GUI.progressBarTick.emit(str(pagenumber))
|
GUI.progressBarTick.emit(str(pagenumber))
|
||||||
@@ -290,7 +267,8 @@ def main(argv=None, qtGUI=None):
|
|||||||
raise UserWarning("Conversion interrupted.")
|
raise UserWarning("Conversion interrupted.")
|
||||||
if len(splitWorkerOutput) > 0:
|
if len(splitWorkerOutput) > 0:
|
||||||
rmtree(options.targetDir, True)
|
rmtree(options.targetDir, True)
|
||||||
raise RuntimeError("One of workers crashed. Cause: " + splitWorkerOutput[0][0], splitWorkerOutput[0][1])
|
raise RuntimeError("One of workers crashed. Cause: " + splitWorkerOutput[0][0],
|
||||||
|
splitWorkerOutput[0][1])
|
||||||
if options.inPlace:
|
if options.inPlace:
|
||||||
rmtree(options.sourceDir)
|
rmtree(options.sourceDir)
|
||||||
move(options.targetDir, options.sourceDir)
|
move(options.targetDir, options.sourceDir)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Based on initial version of DualMetaFix. Copyright (C) 2013 Kevin Hendricks
|
# Based on initial version of DualMetaFix. Copyright (C) 2013 Kevin Hendricks
|
||||||
# Changes for KCC Copyright (C) 2014-2017 Pawel Jastrzebski <pawelj@iosphe.re>
|
# Changes for KCC Copyright (C) 2014-2018 Pawel Jastrzebski <pawelj@iosphe.re>
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# 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
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
# Copyright (C) 2011 Stanislav (proDOOMman) Kosolapov <prodoomman@gmail.com>
|
# Copyright (C) 2011 Stanislav (proDOOMman) Kosolapov <prodoomman@gmail.com>
|
||||||
# Copyright (c) 2016 Alberto Planas <aplanas@gmail.com>
|
# Copyright (c) 2016 Alberto Planas <aplanas@gmail.com>
|
||||||
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
||||||
# Copyright (c) 2013-2017 Pawel Jastrzebski <pawelj@iosphe.re>
|
# Copyright (c) 2013-2018 Pawel Jastrzebski <pawelj@iosphe.re>
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# 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
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -80,11 +80,12 @@ class ProfileData:
|
|||||||
Profiles = {
|
Profiles = {
|
||||||
'K1': ("Kindle 1", (600, 670), Palette4, 1.8),
|
'K1': ("Kindle 1", (600, 670), Palette4, 1.8),
|
||||||
'K2': ("Kindle 2", (600, 670), Palette15, 1.8),
|
'K2': ("Kindle 2", (600, 670), Palette15, 1.8),
|
||||||
'K3': ("Kindle", (600, 800), Palette16, 1.8),
|
'K34': ("Kindle Keyboard/Touch", (600, 800), Palette16, 1.8),
|
||||||
'K45': ("Kindle", (600, 800), Palette16, 1.8),
|
'K578': ("Kindle", (600, 800), Palette16, 1.8),
|
||||||
'KDX': ("Kindle DX/DXG", (824, 1000), Palette16, 1.8),
|
'KDX': ("Kindle DX/DXG", (824, 1000), Palette16, 1.8),
|
||||||
'KPW': ("Kindle Paperwhite 1/2", (758, 1024), Palette16, 1.8),
|
'KPW': ("Kindle Paperwhite 1/2", (758, 1024), Palette16, 1.8),
|
||||||
'KV': ("Kindle Paperwhite 3/Voyage/Oasis", (1072, 1448), Palette16, 1.8),
|
'KV': ("Kindle Paperwhite 3/Voyage/Oasis", (1072, 1448), Palette16, 1.8),
|
||||||
|
'KO': ("Kindle Oasis 2", (1264, 1680), Palette16, 1.8),
|
||||||
'KoMT': ("Kobo Mini/Touch", (600, 800), Palette16, 1.8),
|
'KoMT': ("Kobo Mini/Touch", (600, 800), Palette16, 1.8),
|
||||||
'KoG': ("Kobo Glo", (768, 1024), Palette16, 1.8),
|
'KoG': ("Kobo Glo", (768, 1024), Palette16, 1.8),
|
||||||
'KoGHD': ("Kobo Glo HD", (1072, 1448), Palette16, 1.8),
|
'KoGHD': ("Kobo Glo HD", (1072, 1448), Palette16, 1.8),
|
||||||
@@ -120,7 +121,7 @@ class ComicPageParser:
|
|||||||
width, height = self.image.size
|
width, height = self.image.size
|
||||||
dstwidth, dstheight = self.size
|
dstwidth, dstheight = self.size
|
||||||
if (width > height) != (dstwidth > dstheight) and width <= dstheight and height <= dstwidth \
|
if (width > height) != (dstwidth > dstheight) and width <= dstheight and height <= dstwidth \
|
||||||
and not self.opt.webtoon:
|
and not self.opt.webtoon and self.opt.splitter == 1:
|
||||||
self.payload.append(['R', self.source, self.image.rotate(90, Image.BICUBIC, True), self.color, self.fill])
|
self.payload.append(['R', self.source, self.image.rotate(90, Image.BICUBIC, True), self.color, self.fill])
|
||||||
elif (width > height) != (dstwidth > dstheight) and not self.opt.webtoon:
|
elif (width > height) != (dstwidth > dstheight) and not self.opt.webtoon:
|
||||||
if self.opt.splitter != 1:
|
if self.opt.splitter != 1:
|
||||||
@@ -206,9 +207,11 @@ class ComicPageParser:
|
|||||||
|
|
||||||
|
|
||||||
class ComicPage:
|
class ComicPage:
|
||||||
def __init__(self, mode, path, image, color, fill, options):
|
def __init__(self, options, mode, path, image, color, fill):
|
||||||
self.opt = options
|
self.opt = options
|
||||||
_, self.size, self.palette, self.gamma = self.opt.profileData
|
_, self.size, self.palette, self.gamma = self.opt.profileData
|
||||||
|
if self.opt.hq:
|
||||||
|
self.size = (int(self.size[0] * 1.5), int(self.size[1] * 1.5))
|
||||||
self.image = image
|
self.image = image
|
||||||
self.color = color
|
self.color = color
|
||||||
self.fill = fill
|
self.fill = fill
|
||||||
@@ -232,16 +235,16 @@ class ComicPage:
|
|||||||
if self.rotated:
|
if self.rotated:
|
||||||
flags.append('Rotated')
|
flags.append('Rotated')
|
||||||
if self.fill != 'white':
|
if self.fill != 'white':
|
||||||
flags.append('BlackFill')
|
flags.append('BlackBackground')
|
||||||
if self.opt.forcepng:
|
if self.opt.forcepng:
|
||||||
self.targetPath += '.png'
|
self.targetPath += '.png'
|
||||||
self.image.save(self.targetPath, 'PNG', optimize=1)
|
self.image.save(self.targetPath, 'PNG', optimize=1)
|
||||||
else:
|
else:
|
||||||
self.targetPath += '.jpg'
|
self.targetPath += '.jpg'
|
||||||
self.image.save(self.targetPath, 'JPEG', optimize=1, quality=80)
|
self.image.save(self.targetPath, 'JPEG', optimize=1, quality=85)
|
||||||
return [md5Checksum(self.targetPath), flags, self.orgPath]
|
return [md5Checksum(self.targetPath), flags, self.orgPath]
|
||||||
except IOError:
|
except IOError as err:
|
||||||
raise RuntimeError('Cannot save image.')
|
raise RuntimeError('Cannot save image. ' + str(err))
|
||||||
|
|
||||||
def autocontrastImage(self):
|
def autocontrastImage(self):
|
||||||
gamma = self.opt.gamma
|
gamma = self.opt.gamma
|
||||||
@@ -270,17 +273,17 @@ class ComicPage:
|
|||||||
method = Image.BICUBIC
|
method = Image.BICUBIC
|
||||||
else:
|
else:
|
||||||
method = Image.LANCZOS
|
method = Image.LANCZOS
|
||||||
if self.opt.stretch:
|
if self.opt.stretch or (self.opt.kfx and ('-KCC-B' in self.targetPath or '-KCC-C' in self.targetPath)):
|
||||||
self.image = self.image.resize(self.size, method)
|
self.image = self.image.resize(self.size, method)
|
||||||
elif self.image.size[0] <= self.size[0] and self.image.size[1] <= self.size[1] and not self.opt.upscale:
|
elif self.image.size[0] <= self.size[0] and self.image.size[1] <= self.size[1] and not self.opt.upscale:
|
||||||
if self.opt.format == 'CBZ':
|
if self.opt.format == 'CBZ' or self.opt.kfx:
|
||||||
borderw = int((self.size[0] - self.image.size[0]) / 2)
|
borderw = int((self.size[0] - self.image.size[0]) / 2)
|
||||||
borderh = int((self.size[1] - self.image.size[1]) / 2)
|
borderh = int((self.size[1] - self.image.size[1]) / 2)
|
||||||
self.image = ImageOps.expand(self.image, border=(borderw, borderh), fill=self.fill)
|
self.image = ImageOps.expand(self.image, border=(borderw, borderh), fill=self.fill)
|
||||||
if self.image.size[0] != self.size[0] or self.image.size[1] != self.size[1]:
|
if self.image.size[0] != self.size[0] or self.image.size[1] != self.size[1]:
|
||||||
self.image = ImageOps.fit(self.image, self.size, method=Image.BICUBIC, centering=(0.5, 0.5))
|
self.image = ImageOps.fit(self.image, self.size, method=Image.BICUBIC, centering=(0.5, 0.5))
|
||||||
else:
|
else:
|
||||||
if self.opt.format == 'CBZ':
|
if self.opt.format == 'CBZ' or self.opt.kfx:
|
||||||
ratioDev = float(self.size[0]) / float(self.size[1])
|
ratioDev = float(self.size[0]) / float(self.size[1])
|
||||||
if (float(self.image.size[0]) / float(self.image.size[1])) < ratioDev:
|
if (float(self.image.size[0]) / float(self.image.size[1])) < ratioDev:
|
||||||
diff = int(self.image.size[1] * ratioDev) - self.image.size[0]
|
diff = int(self.image.size[1] * ratioDev) - self.image.size[0]
|
||||||
@@ -296,53 +299,53 @@ class ComicPage:
|
|||||||
if self.image.size[0] > self.size[0] or self.image.size[1] > self.size[1]:
|
if self.image.size[0] > self.size[0] or self.image.size[1] > self.size[1]:
|
||||||
self.image.thumbnail(self.size, Image.LANCZOS)
|
self.image.thumbnail(self.size, Image.LANCZOS)
|
||||||
|
|
||||||
def getBoundingBox(self, tmpImg):
|
def getBoundingBox(self, tmptmg):
|
||||||
min_margin = [int(0.005 * i + 0.5) for i in tmpImg.size]
|
min_margin = [int(0.005 * i + 0.5) for i in tmptmg.size]
|
||||||
max_margin = [int(0.1 * i + 0.5) for i in tmpImg.size]
|
max_margin = [int(0.1 * i + 0.5) for i in tmptmg.size]
|
||||||
bbox = tmpImg.getbbox()
|
bbox = tmptmg.getbbox()
|
||||||
bbox = (
|
bbox = (
|
||||||
max(0, min(max_margin[0], bbox[0] - min_margin[0])),
|
max(0, min(max_margin[0], bbox[0] - min_margin[0])),
|
||||||
max(0, min(max_margin[1], bbox[1] - min_margin[1])),
|
max(0, min(max_margin[1], bbox[1] - min_margin[1])),
|
||||||
min(tmpImg.size[0],
|
min(tmptmg.size[0],
|
||||||
max(tmpImg.size[0] - max_margin[0], bbox[2] + min_margin[0])),
|
max(tmptmg.size[0] - max_margin[0], bbox[2] + min_margin[0])),
|
||||||
min(tmpImg.size[1],
|
min(tmptmg.size[1],
|
||||||
max(tmpImg.size[1] - max_margin[1], bbox[3] + min_margin[1])),
|
max(tmptmg.size[1] - max_margin[1], bbox[3] + min_margin[1])),
|
||||||
)
|
)
|
||||||
return bbox
|
return bbox
|
||||||
|
|
||||||
def cropPageNumber(self, power):
|
def cropPageNumber(self, power):
|
||||||
if self.fill != 'white':
|
if self.fill != 'white':
|
||||||
tmpImg = self.image.convert(mode='L')
|
tmptmg = self.image.convert(mode='L')
|
||||||
else:
|
else:
|
||||||
tmpImg = ImageOps.invert(self.image.convert(mode='L'))
|
tmptmg = ImageOps.invert(self.image.convert(mode='L'))
|
||||||
tmpImg = tmpImg.point(lambda x: x and 255)
|
tmptmg = tmptmg.point(lambda x: x and 255)
|
||||||
tmpImg = tmpImg.filter(ImageFilter.MinFilter(size=3))
|
tmptmg = tmptmg.filter(ImageFilter.MinFilter(size=3))
|
||||||
tmpImg = tmpImg.filter(ImageFilter.GaussianBlur(radius=5))
|
tmptmg = tmptmg.filter(ImageFilter.GaussianBlur(radius=5))
|
||||||
tmpImg = tmpImg.point(lambda x: (x >= 16 * power) and x)
|
tmptmg = tmptmg.point(lambda x: (x >= 16 * power) and x)
|
||||||
self.image = self.image.crop(tmpImg.getbbox()) if tmpImg.getbbox() else self.image
|
self.image = self.image.crop(tmptmg.getbbox()) if tmptmg.getbbox() else self.image
|
||||||
|
|
||||||
def cropMargin(self, power):
|
def cropMargin(self, power):
|
||||||
if self.fill != 'white':
|
if self.fill != 'white':
|
||||||
tmpImg = self.image.convert(mode='L')
|
tmptmg = self.image.convert(mode='L')
|
||||||
else:
|
else:
|
||||||
tmpImg = ImageOps.invert(self.image.convert(mode='L'))
|
tmptmg = ImageOps.invert(self.image.convert(mode='L'))
|
||||||
tmpImg = tmpImg.filter(ImageFilter.GaussianBlur(radius=3))
|
tmptmg = tmptmg.filter(ImageFilter.GaussianBlur(radius=3))
|
||||||
tmpImg = tmpImg.point(lambda x: (x >= 16 * power) and x)
|
tmptmg = tmptmg.point(lambda x: (x >= 16 * power) and x)
|
||||||
self.image = self.image.crop(self.getBoundingBox(tmpImg)) if tmpImg.getbbox() else self.image
|
self.image = self.image.crop(self.getBoundingBox(tmptmg)) if tmptmg.getbbox() else self.image
|
||||||
|
|
||||||
|
|
||||||
class Cover:
|
class Cover:
|
||||||
def __init__(self, source, target, opt, tomeNumber):
|
def __init__(self, source, target, opt, tomeid):
|
||||||
self.options = opt
|
self.options = opt
|
||||||
self.source = source
|
self.source = source
|
||||||
self.target = target
|
self.target = target
|
||||||
if tomeNumber == 0:
|
if tomeid == 0:
|
||||||
self.tomeNumber = 1
|
self.tomeid = 1
|
||||||
else:
|
else:
|
||||||
self.tomeNumber = tomeNumber
|
self.tomeid = tomeid
|
||||||
if self.tomeNumber in self.options.remoteCovers:
|
if self.tomeid in self.options.remoteCovers:
|
||||||
try:
|
try:
|
||||||
source = urlopen(Request(quote(self.options.remoteCovers[self.tomeNumber]).replace('%3A', ':', 1),
|
source = urlopen(Request(quote(self.options.remoteCovers[self.tomeid]).replace('%3A', ':', 1),
|
||||||
headers={'User-Agent': 'KindleComicConverter/' + __version__})).read()
|
headers={'User-Agent': 'KindleComicConverter/' + __version__})).read()
|
||||||
self.image = Image.open(BytesIO(source))
|
self.image = Image.open(BytesIO(source))
|
||||||
except Exception:
|
except Exception:
|
||||||
@@ -361,7 +364,7 @@ class Cover:
|
|||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
try:
|
try:
|
||||||
self.image.save(self.target, "JPEG", optimize=1, quality=80)
|
self.image.save(self.target, "JPEG", optimize=1, quality=85)
|
||||||
except IOError:
|
except IOError:
|
||||||
raise RuntimeError('Failed to process downloaded cover.')
|
raise RuntimeError('Failed to process downloaded cover.')
|
||||||
|
|
||||||
@@ -369,6 +372,6 @@ class Cover:
|
|||||||
self.image = self.image.resize((300, 470), Image.ANTIALIAS)
|
self.image = self.image.resize((300, 470), Image.ANTIALIAS)
|
||||||
try:
|
try:
|
||||||
self.image.save(os.path.join(kindle.path.split('documents')[0], 'system', 'thumbnails',
|
self.image.save(os.path.join(kindle.path.split('documents')[0], 'system', 'thumbnails',
|
||||||
'thumbnail_' + asin + '_EBOK_portrait.jpg'), 'JPEG')
|
'thumbnail_' + asin + '_EBOK_portrait.jpg'), 'JPEG', optimize=1, quality=85)
|
||||||
except IOError:
|
except IOError:
|
||||||
raise RuntimeError('Failed to upload cover.')
|
raise RuntimeError('Failed to upload cover.')
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Copyright (c) 2013-2017 Pawel Jastrzebski <pawelj@iosphe.re>
|
# Copyright (c) 2013-2018 Pawel Jastrzebski <pawelj@iosphe.re>
|
||||||
#
|
#
|
||||||
# Permission to use, copy, modify, and/or distribute this software for
|
# Permission to use, copy, modify, and/or distribute this software for
|
||||||
# any purpose with or without fee is hereby granted, provided that the
|
# any purpose with or without fee is hereby granted, provided that the
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Copyright (c) 2013-2017 Pawel Jastrzebski <pawelj@iosphe.re>
|
# Copyright (c) 2013-2018 Pawel Jastrzebski <pawelj@iosphe.re>
|
||||||
#
|
#
|
||||||
# Permission to use, copy, modify, and/or distribute this software for
|
# Permission to use, copy, modify, and/or distribute this software for
|
||||||
# any purpose with or without fee is hereby granted, provided that the
|
# any purpose with or without fee is hereby granted, provided that the
|
||||||
@@ -43,10 +43,10 @@ class MetadataParser:
|
|||||||
'Bookmarks': []}
|
'Bookmarks': []}
|
||||||
self.rawdata = None
|
self.rawdata = None
|
||||||
self.compressor = None
|
self.compressor = None
|
||||||
if self.source.endswith('.xml'):
|
if self.source.endswith('.xml') and os.path.exists(self.source):
|
||||||
self.rawdata = parse(self.source)
|
self.rawdata = parse(self.source)
|
||||||
self.parseXML()
|
self.parseXML()
|
||||||
else:
|
elif not self.source.endswith('.xml'):
|
||||||
if is_zipfile(self.source):
|
if is_zipfile(self.source):
|
||||||
self.compressor = 'zip'
|
self.compressor = 'zip'
|
||||||
with ZipFile(self.source) as zip_file:
|
with ZipFile(self.source) as zip_file:
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
||||||
# Copyright (c) 2013-2017 Pawel Jastrzebski <pawelj@iosphe.re>
|
# Copyright (c) 2013-2018 Pawel Jastrzebski <pawelj@iosphe.re>
|
||||||
#
|
#
|
||||||
# Based upon the code snippet by Ned Batchelder
|
# Based upon the code snippet by Ned Batchelder
|
||||||
# (http://nedbatchelder.com/blog/200712/extracting_jpgs_from_pdfs.html)
|
# (http://nedbatchelder.com/blog/200712/extracting_jpgs_from_pdfs.html)
|
||||||
@@ -25,17 +25,16 @@ from string import ascii_uppercase, digits
|
|||||||
|
|
||||||
|
|
||||||
class PdfJpgExtract:
|
class PdfJpgExtract:
|
||||||
def __init__(self, origFileName):
|
def __init__(self, fname):
|
||||||
self.origFileName = origFileName
|
self.fname = fname
|
||||||
self.filename = os.path.splitext(origFileName)
|
self.filename = os.path.splitext(fname)
|
||||||
# noinspection PyUnusedLocal
|
self.path = self.filename[0] + "-KCC-" + ''.join(choice(ascii_uppercase + digits) for _ in range(3))
|
||||||
self.path = self.filename[0] + "-KCC-" + ''.join(choice(ascii_uppercase + digits) for x in range(3))
|
|
||||||
|
|
||||||
def getPath(self):
|
def getPath(self):
|
||||||
return self.path
|
return self.path
|
||||||
|
|
||||||
def extract(self):
|
def extract(self):
|
||||||
pdf = open(self.origFileName, "rb").read()
|
pdf = open(self.fname, "rb").read()
|
||||||
startmark = b"\xff\xd8"
|
startmark = b"\xff\xd8"
|
||||||
startfix = 0
|
startfix = 0
|
||||||
endmark = b"\xff\xd9"
|
endmark = b"\xff\xd9"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
||||||
# Copyright (c) 2013-2017 Pawel Jastrzebski <pawelj@iosphe.re>
|
# Copyright (c) 2013-2018 Pawel Jastrzebski <pawelj@iosphe.re>
|
||||||
#
|
#
|
||||||
# Permission to use, copy, modify, and/or distribute this software for
|
# Permission to use, copy, modify, and/or distribute this software for
|
||||||
# any purpose with or without fee is hereby granted, provided that the
|
# any purpose with or without fee is hereby granted, provided that the
|
||||||
@@ -17,20 +17,14 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from sys import version_info
|
|
||||||
from hashlib import md5
|
from hashlib import md5
|
||||||
from html.parser import HTMLParser
|
from html.parser import HTMLParser
|
||||||
from distutils.version import StrictVersion
|
from distutils.version import StrictVersion
|
||||||
from time import sleep
|
|
||||||
from shutil import rmtree, copy
|
from shutil import rmtree, copy
|
||||||
from tempfile import mkdtemp
|
from tempfile import mkdtemp
|
||||||
from zipfile import ZipFile, ZIP_DEFLATED
|
from zipfile import ZipFile, ZIP_DEFLATED
|
||||||
from re import split
|
from re import split
|
||||||
from traceback import format_tb
|
from traceback import format_tb
|
||||||
try:
|
|
||||||
from scandir import walk
|
|
||||||
except ImportError:
|
|
||||||
walk = os.walk
|
|
||||||
|
|
||||||
|
|
||||||
class HTMLStripper(HTMLParser):
|
class HTMLStripper(HTMLParser):
|
||||||
@@ -71,7 +65,7 @@ def walkLevel(some_dir, level=1):
|
|||||||
some_dir = some_dir.rstrip(os.path.sep)
|
some_dir = some_dir.rstrip(os.path.sep)
|
||||||
assert os.path.isdir(some_dir)
|
assert os.path.isdir(some_dir)
|
||||||
num_sep = some_dir.count(os.path.sep)
|
num_sep = some_dir.count(os.path.sep)
|
||||||
for root, dirs, files in walk(some_dir):
|
for root, dirs, files in os.walk(some_dir):
|
||||||
dirs, files = walkSort(dirs, files)
|
dirs, files = walkSort(dirs, files)
|
||||||
yield root, dirs, files
|
yield root, dirs, files
|
||||||
num_sep_this = root.count(os.path.sep)
|
num_sep_this = root.count(os.path.sep)
|
||||||
@@ -79,8 +73,8 @@ def walkLevel(some_dir, level=1):
|
|||||||
del dirs[:]
|
del dirs[:]
|
||||||
|
|
||||||
|
|
||||||
def md5Checksum(filePath):
|
def md5Checksum(fpath):
|
||||||
with open(filePath, 'rb') as fh:
|
with open(fpath, 'rb') as fh:
|
||||||
m = md5()
|
m = md5()
|
||||||
while True:
|
while True:
|
||||||
data = fh.read(8192)
|
data = fh.read(8192)
|
||||||
@@ -90,36 +84,12 @@ def md5Checksum(filePath):
|
|||||||
return m.hexdigest()
|
return m.hexdigest()
|
||||||
|
|
||||||
|
|
||||||
def check7ZFile(filePath):
|
def check7ZFile(fpath):
|
||||||
with open(filePath, 'rb') as fh:
|
with open(fpath, 'rb') as fh:
|
||||||
header = fh.read(6)
|
header = fh.read(6)
|
||||||
return header == b"7z\xbc\xaf'\x1c"
|
return header == b"7z\xbc\xaf'\x1c"
|
||||||
|
|
||||||
|
|
||||||
def saferReplace(old, new):
|
|
||||||
for x in range(30):
|
|
||||||
try:
|
|
||||||
os.replace(old, new)
|
|
||||||
except PermissionError:
|
|
||||||
sleep(1)
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
raise PermissionError("Failed to move the file.")
|
|
||||||
|
|
||||||
|
|
||||||
def saferRemove(target):
|
|
||||||
for x in range(30):
|
|
||||||
try:
|
|
||||||
os.remove(target)
|
|
||||||
except PermissionError:
|
|
||||||
sleep(1)
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
raise PermissionError("Failed to remove the file.")
|
|
||||||
|
|
||||||
|
|
||||||
def removeFromZIP(zipfname, *filenames):
|
def removeFromZIP(zipfname, *filenames):
|
||||||
tempdir = mkdtemp('', 'KCC-')
|
tempdir = mkdtemp('', 'KCC-')
|
||||||
try:
|
try:
|
||||||
@@ -129,27 +99,21 @@ def removeFromZIP(zipfname, *filenames):
|
|||||||
for item in zipread.infolist():
|
for item in zipread.infolist():
|
||||||
if item.filename not in filenames:
|
if item.filename not in filenames:
|
||||||
zipwrite.writestr(item, zipread.read(item.filename))
|
zipwrite.writestr(item, zipread.read(item.filename))
|
||||||
for x in range(30):
|
copy(tempname, zipfname)
|
||||||
try:
|
|
||||||
copy(tempname, zipfname)
|
|
||||||
except PermissionError:
|
|
||||||
sleep(1)
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
raise PermissionError
|
|
||||||
finally:
|
finally:
|
||||||
rmtree(tempdir, True)
|
rmtree(tempdir, True)
|
||||||
|
|
||||||
|
|
||||||
def sanitizeTrace(traceback):
|
def sanitizeTrace(traceback):
|
||||||
return ''.join(format_tb(traceback))\
|
return ''.join(format_tb(traceback))\
|
||||||
.replace('C:/Users/Pawel/Documents/Projekty/KCC/', '')\
|
.replace('C:/projects/kcc/', '') \
|
||||||
.replace('C:/Python35/', '')\
|
.replace('c:/projects/kcc/', '') \
|
||||||
.replace('c:/python35/', '')\
|
.replace('C:/python36-x64/', '')\
|
||||||
.replace('C:\\Users\\Pawel\\Documents\\Projekty\\KCC\\', '')\
|
.replace('c:/python36-x64/', '')\
|
||||||
.replace('C:\\Python35\\', '')\
|
.replace('C:\\projects\\kcc\\', '') \
|
||||||
.replace('c:\\python35\\', '')
|
.replace('c:\\projects\\kcc\\', '') \
|
||||||
|
.replace('C:\\python36-x64\\', '')\
|
||||||
|
.replace('c:\\python36-x64\\', '')
|
||||||
|
|
||||||
|
|
||||||
def dependencyCheck(level):
|
def dependencyCheck(level):
|
||||||
@@ -164,33 +128,26 @@ def dependencyCheck(level):
|
|||||||
try:
|
try:
|
||||||
import raven
|
import raven
|
||||||
except ImportError:
|
except ImportError:
|
||||||
missing.append('raven 5.13.0+')
|
missing.append('raven 6.0.0+')
|
||||||
if level > 1:
|
if level > 1:
|
||||||
try:
|
try:
|
||||||
from psutil import __version__ as psutilVersion
|
from psutil import __version__ as psutilVersion
|
||||||
if StrictVersion('4.1.0') > StrictVersion(psutilVersion):
|
if StrictVersion('5.0.0') > StrictVersion(psutilVersion):
|
||||||
missing.append('psutil 4.1.0+')
|
missing.append('psutil 5.0.0+')
|
||||||
except ImportError:
|
except ImportError:
|
||||||
missing.append('psutil 4.1.0+')
|
missing.append('psutil 5.0.0+')
|
||||||
try:
|
try:
|
||||||
from slugify import __version__ as slugifyVersion
|
from slugify import __version__ as slugifyVersion
|
||||||
if StrictVersion('1.2.0') > StrictVersion(slugifyVersion):
|
if StrictVersion('1.2.1') > StrictVersion(slugifyVersion):
|
||||||
missing.append('python-slugify 1.2.0+')
|
missing.append('python-slugify 1.2.1+')
|
||||||
except ImportError:
|
except ImportError:
|
||||||
missing.append('python-slugify 1.2.0+')
|
missing.append('python-slugify 1.2.1+')
|
||||||
try:
|
try:
|
||||||
from PIL import PILLOW_VERSION as pillowVersion
|
from PIL import PILLOW_VERSION as pillowVersion
|
||||||
if StrictVersion('3.2.0') > StrictVersion(pillowVersion):
|
if StrictVersion('4.0.0') > StrictVersion(pillowVersion):
|
||||||
missing.append('Pillow 3.2.0+')
|
missing.append('Pillow 4.0.0+')
|
||||||
except ImportError:
|
except ImportError:
|
||||||
missing.append('Pillow 3.2.0+')
|
missing.append('Pillow 4.0.0+')
|
||||||
if version_info[1] < 5:
|
|
||||||
try:
|
|
||||||
from scandir import __version__ as scandirVersion
|
|
||||||
if StrictVersion('1.2') > StrictVersion(scandirVersion):
|
|
||||||
missing.append('scandir 1.2+')
|
|
||||||
except ImportError:
|
|
||||||
missing.append('scandir 1.2+')
|
|
||||||
if len(missing) > 0:
|
if len(missing) > 0:
|
||||||
print('ERROR: ' + ', '.join(missing) + ' is not installed!')
|
print('ERROR: ' + ', '.join(missing) + ' is not installed!')
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|||||||
56
kindlecomicconverter/startup.py
Normal file
56
kindlecomicconverter/startup.py
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
||||||
|
# Copyright (c) 2013-2018 Pawel Jastrzebski <pawelj@iosphe.re>
|
||||||
|
#
|
||||||
|
# Permission to use, copy, modify, and/or distribute this software for
|
||||||
|
# any purpose with or without fee is hereby granted, provided that the
|
||||||
|
# above copyright notice and this permission notice appear in all
|
||||||
|
# copies.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||||
|
# WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||||
|
# WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
||||||
|
# AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
# DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
|
||||||
|
# OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||||
|
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
|
# PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
#
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from . import __version__
|
||||||
|
from .shared import dependencyCheck
|
||||||
|
|
||||||
|
|
||||||
|
def start():
|
||||||
|
dependencyCheck(3)
|
||||||
|
from . import KCC_gui
|
||||||
|
os.environ['QT_AUTO_SCREEN_SCALE_FACTOR'] = "1"
|
||||||
|
KCCAplication = KCC_gui.QApplicationMessaging(sys.argv)
|
||||||
|
if KCCAplication.isRunning():
|
||||||
|
if len(sys.argv) > 1:
|
||||||
|
KCCAplication.sendMessage(sys.argv[1])
|
||||||
|
else:
|
||||||
|
KCCAplication.sendMessage('ARISE')
|
||||||
|
else:
|
||||||
|
KCCWindow = KCC_gui.QMainWindowKCC()
|
||||||
|
KCCUI = KCC_gui.KCCGUI(KCCAplication, KCCWindow)
|
||||||
|
if len(sys.argv) > 1:
|
||||||
|
KCCUI.handleMessage(sys.argv[1])
|
||||||
|
sys.exit(KCCAplication.exec_())
|
||||||
|
|
||||||
|
|
||||||
|
def startC2E():
|
||||||
|
dependencyCheck(2)
|
||||||
|
from .comic2ebook import main
|
||||||
|
print('comic2ebook v' + __version__ + ' - Written by Ciro Mattia Gonano and Pawel Jastrzebski.')
|
||||||
|
sys.exit(main(sys.argv[1:]))
|
||||||
|
|
||||||
|
|
||||||
|
def startC2P():
|
||||||
|
dependencyCheck(1)
|
||||||
|
from .comic2panel import main
|
||||||
|
print('comic2panel v' + __version__ + ' - Written by Ciro Mattia Gonano and Pawel Jastrzebski.')
|
||||||
|
sys.exit(main(sys.argv[1:]))
|
||||||
BIN
other/linux/sentry.py.enc
Normal file
BIN
other/linux/sentry.py.enc
Normal file
Binary file not shown.
@@ -30,7 +30,7 @@
|
|||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
<string>MacOS/Kindle Comic Converter</string>
|
<string>MacOS/Kindle Comic Converter</string>
|
||||||
<key>CFBundleGetInfoString</key>
|
<key>CFBundleGetInfoString</key>
|
||||||
<string>KindleComicConverter 5.3.0, written 2012-2017 by Ciro Mattia Gonano and Pawel Jastrzebski</string>
|
<string>KindleComicConverter 5.4.4, written 2012-2018 by Ciro Mattia Gonano and Pawel Jastrzebski</string>
|
||||||
<key>CFBundleIconFile</key>
|
<key>CFBundleIconFile</key>
|
||||||
<string>comic2ebook.icns</string>
|
<string>comic2ebook.icns</string>
|
||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
@@ -42,11 +42,11 @@
|
|||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>5.3.0</string>
|
<string>5.4.4</string>
|
||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>????</string>
|
<string>????</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>5.3.0</string>
|
<string>5.4.4</string>
|
||||||
<key>LSEnvironment</key>
|
<key>LSEnvironment</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>PATH</key>
|
<key>PATH</key>
|
||||||
@@ -55,7 +55,7 @@
|
|||||||
<key>LSHasLocalizedDisplayName</key>
|
<key>LSHasLocalizedDisplayName</key>
|
||||||
<false/>
|
<false/>
|
||||||
<key>LSMinimumSystemVersion</key>
|
<key>LSMinimumSystemVersion</key>
|
||||||
<string>10.9.0</string>
|
<string>10.10.0</string>
|
||||||
<key>NSAppleScriptEnabled</key>
|
<key>NSAppleScriptEnabled</key>
|
||||||
<false/>
|
<false/>
|
||||||
<key>NSHumanReadableCopyright</key>
|
<key>NSHumanReadableCopyright</key>
|
||||||
|
|||||||
BIN
other/osx/sentry.py.enc
Normal file
BIN
other/osx/sentry.py.enc
Normal file
Binary file not shown.
@@ -3,19 +3,20 @@
|
|||||||
{\flomajor\f31500\fbidi \froman\fcharset238\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\fdbmajor\f31501\fbidi \froman\fcharset238\fprq2{\*\panose 02020603050405020304}Times New Roman;}
|
{\flomajor\f31500\fbidi \froman\fcharset238\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\fdbmajor\f31501\fbidi \froman\fcharset238\fprq2{\*\panose 02020603050405020304}Times New Roman;}
|
||||||
{\fhimajor\f31502\fbidi \fswiss\fcharset238\fprq2{\*\panose 020f0302020204030204}Calibri Light;}{\fbimajor\f31503\fbidi \froman\fcharset238\fprq2{\*\panose 02020603050405020304}Times New Roman;}
|
{\fhimajor\f31502\fbidi \fswiss\fcharset238\fprq2{\*\panose 020f0302020204030204}Calibri Light;}{\fbimajor\f31503\fbidi \froman\fcharset238\fprq2{\*\panose 02020603050405020304}Times New Roman;}
|
||||||
{\flominor\f31504\fbidi \froman\fcharset238\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\fdbminor\f31505\fbidi \froman\fcharset238\fprq2{\*\panose 02020603050405020304}Times New Roman;}
|
{\flominor\f31504\fbidi \froman\fcharset238\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\fdbminor\f31505\fbidi \froman\fcharset238\fprq2{\*\panose 02020603050405020304}Times New Roman;}
|
||||||
{\fhiminor\f31506\fbidi \fswiss\fcharset238\fprq2{\*\panose 020f0502020204030204}Calibri;}{\fbiminor\f31507\fbidi \froman\fcharset238\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f41\fbidi \froman\fcharset0\fprq2 Times New Roman;}
|
{\fhiminor\f31506\fbidi \fswiss\fcharset238\fprq2{\*\panose 020f0502020204030204}Calibri;}{\fbiminor\f31507\fbidi \froman\fcharset238\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f44\fbidi \froman\fcharset0\fprq2 Times New Roman;}
|
||||||
{\f40\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\f42\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\f43\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\f44\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}
|
{\f43\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\f45\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\f46\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\f47\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}
|
||||||
{\f45\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\f46\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\f47\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\f41\fbidi \froman\fcharset0\fprq2 Times New Roman;}
|
{\f48\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\f49\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\f50\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\f44\fbidi \froman\fcharset0\fprq2 Times New Roman;}
|
||||||
{\f40\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\f42\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\f43\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\f44\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}
|
{\f43\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\f45\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\f46\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\f47\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}
|
||||||
{\f45\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\f46\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\f47\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\f411\fbidi \fswiss\fcharset0\fprq2 Calibri;}
|
{\f48\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\f49\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\f50\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\f414\fbidi \fswiss\fcharset0\fprq2 Calibri;}
|
||||||
{\f410\fbidi \fswiss\fcharset204\fprq2 Calibri Cyr;}{\f412\fbidi \fswiss\fcharset161\fprq2 Calibri Greek;}{\f413\fbidi \fswiss\fcharset162\fprq2 Calibri Tur;}{\f416\fbidi \fswiss\fcharset186\fprq2 Calibri Baltic;}
|
{\f413\fbidi \fswiss\fcharset204\fprq2 Calibri Cyr;}{\f415\fbidi \fswiss\fcharset161\fprq2 Calibri Greek;}{\f416\fbidi \fswiss\fcharset162\fprq2 Calibri Tur;}{\f417\fbidi \fswiss\fcharset177\fprq2 Calibri (Hebrew);}
|
||||||
{\f417\fbidi \fswiss\fcharset163\fprq2 Calibri (Vietnamese);}{\flomajor\f31510\fbidi \froman\fcharset0\fprq2 Times New Roman;}{\flomajor\f31509\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}
|
{\f418\fbidi \fswiss\fcharset178\fprq2 Calibri (Arabic);}{\f419\fbidi \fswiss\fcharset186\fprq2 Calibri Baltic;}{\f420\fbidi \fswiss\fcharset163\fprq2 Calibri (Vietnamese);}{\flomajor\f31510\fbidi \froman\fcharset0\fprq2 Times New Roman;}
|
||||||
{\flomajor\f31511\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\flomajor\f31512\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\flomajor\f31513\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}
|
{\flomajor\f31509\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\flomajor\f31511\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\flomajor\f31512\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}
|
||||||
{\flomajor\f31514\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\flomajor\f31515\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\flomajor\f31516\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}
|
{\flomajor\f31513\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\flomajor\f31514\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\flomajor\f31515\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}
|
||||||
{\fdbmajor\f31520\fbidi \froman\fcharset0\fprq2 Times New Roman;}{\fdbmajor\f31519\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\fdbmajor\f31521\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}
|
{\flomajor\f31516\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fdbmajor\f31520\fbidi \froman\fcharset0\fprq2 Times New Roman;}{\fdbmajor\f31519\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}
|
||||||
{\fdbmajor\f31522\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fdbmajor\f31523\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\fdbmajor\f31524\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}
|
{\fdbmajor\f31521\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fdbmajor\f31522\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fdbmajor\f31523\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}
|
||||||
{\fdbmajor\f31525\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fdbmajor\f31526\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fhimajor\f31530\fbidi \fswiss\fcharset0\fprq2 Calibri Light;}
|
{\fdbmajor\f31524\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fdbmajor\f31525\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fdbmajor\f31526\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}
|
||||||
{\fhimajor\f31529\fbidi \fswiss\fcharset204\fprq2 Calibri Light Cyr;}{\fhimajor\f31531\fbidi \fswiss\fcharset161\fprq2 Calibri Light Greek;}{\fhimajor\f31532\fbidi \fswiss\fcharset162\fprq2 Calibri Light Tur;}
|
{\fhimajor\f31530\fbidi \fswiss\fcharset0\fprq2 Calibri Light;}{\fhimajor\f31529\fbidi \fswiss\fcharset204\fprq2 Calibri Light Cyr;}{\fhimajor\f31531\fbidi \fswiss\fcharset161\fprq2 Calibri Light Greek;}
|
||||||
|
{\fhimajor\f31532\fbidi \fswiss\fcharset162\fprq2 Calibri Light Tur;}{\fhimajor\f31533\fbidi \fswiss\fcharset177\fprq2 Calibri Light (Hebrew);}{\fhimajor\f31534\fbidi \fswiss\fcharset178\fprq2 Calibri Light (Arabic);}
|
||||||
{\fhimajor\f31535\fbidi \fswiss\fcharset186\fprq2 Calibri Light Baltic;}{\fhimajor\f31536\fbidi \fswiss\fcharset163\fprq2 Calibri Light (Vietnamese);}{\fbimajor\f31540\fbidi \froman\fcharset0\fprq2 Times New Roman;}
|
{\fhimajor\f31535\fbidi \fswiss\fcharset186\fprq2 Calibri Light Baltic;}{\fhimajor\f31536\fbidi \fswiss\fcharset163\fprq2 Calibri Light (Vietnamese);}{\fbimajor\f31540\fbidi \froman\fcharset0\fprq2 Times New Roman;}
|
||||||
{\fbimajor\f31539\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\fbimajor\f31541\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fbimajor\f31542\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}
|
{\fbimajor\f31539\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\fbimajor\f31541\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fbimajor\f31542\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}
|
||||||
{\fbimajor\f31543\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\fbimajor\f31544\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fbimajor\f31545\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}
|
{\fbimajor\f31543\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\fbimajor\f31544\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fbimajor\f31545\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}
|
||||||
@@ -26,20 +27,21 @@
|
|||||||
{\fdbminor\f31562\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fdbminor\f31563\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\fdbminor\f31564\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}
|
{\fdbminor\f31562\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fdbminor\f31563\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\fdbminor\f31564\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}
|
||||||
{\fdbminor\f31565\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fdbminor\f31566\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fhiminor\f31570\fbidi \fswiss\fcharset0\fprq2 Calibri;}
|
{\fdbminor\f31565\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fdbminor\f31566\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fhiminor\f31570\fbidi \fswiss\fcharset0\fprq2 Calibri;}
|
||||||
{\fhiminor\f31569\fbidi \fswiss\fcharset204\fprq2 Calibri Cyr;}{\fhiminor\f31571\fbidi \fswiss\fcharset161\fprq2 Calibri Greek;}{\fhiminor\f31572\fbidi \fswiss\fcharset162\fprq2 Calibri Tur;}
|
{\fhiminor\f31569\fbidi \fswiss\fcharset204\fprq2 Calibri Cyr;}{\fhiminor\f31571\fbidi \fswiss\fcharset161\fprq2 Calibri Greek;}{\fhiminor\f31572\fbidi \fswiss\fcharset162\fprq2 Calibri Tur;}
|
||||||
{\fhiminor\f31575\fbidi \fswiss\fcharset186\fprq2 Calibri Baltic;}{\fhiminor\f31576\fbidi \fswiss\fcharset163\fprq2 Calibri (Vietnamese);}{\fbiminor\f31580\fbidi \froman\fcharset0\fprq2 Times New Roman;}
|
{\fhiminor\f31573\fbidi \fswiss\fcharset177\fprq2 Calibri (Hebrew);}{\fhiminor\f31574\fbidi \fswiss\fcharset178\fprq2 Calibri (Arabic);}{\fhiminor\f31575\fbidi \fswiss\fcharset186\fprq2 Calibri Baltic;}
|
||||||
{\fbiminor\f31579\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\fbiminor\f31581\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fbiminor\f31582\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}
|
{\fhiminor\f31576\fbidi \fswiss\fcharset163\fprq2 Calibri (Vietnamese);}{\fbiminor\f31580\fbidi \froman\fcharset0\fprq2 Times New Roman;}{\fbiminor\f31579\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}
|
||||||
{\fbiminor\f31583\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\fbiminor\f31584\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fbiminor\f31585\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}
|
{\fbiminor\f31581\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fbiminor\f31582\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fbiminor\f31583\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}
|
||||||
{\fbiminor\f31586\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;
|
{\fbiminor\f31584\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fbiminor\f31585\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fbiminor\f31586\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}}
|
||||||
\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;\red192\green192\blue192;
|
{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;
|
||||||
\chyperlink\ctint255\cshade255\red5\green99\blue193;\cfollowedhyperlink\ctint255\cshade255\red149\green79\blue114;}{\*\defchp \f31506\fs22\lang1045\langfe1033\langfenp1033 }{\*\defpap \ql \li0\ri0\sa160\sl259\slmult1
|
\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;\red192\green192\blue192;\chyperlink\ctint255\cshade255\red5\green99\blue193;\cfollowedhyperlink\ctint255\cshade255\red149\green79\blue114;}{\*\defchp
|
||||||
\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 }\noqfpromote {\stylesheet{\ql \li0\ri0\sa160\sl259\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs22\alang1025 \ltrch\fcs0
|
\f31506\fs22\lang1045\langfe1033\langfenp1033 }{\*\defpap \ql \li0\ri0\sa160\sl259\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 }\noqfpromote {\stylesheet{\ql \li0\ri0\sa160\sl259\slmult1
|
||||||
\f31506\fs22\lang1045\langfe1033\cgrid\langnp1045\langfenp1033 \snext0 \sqformat \spriority0 Normal;}{\*\cs10 \additive \ssemihidden \sunhideused \spriority1 Default Paragraph Font;}{\*
|
\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs22\alang1025 \ltrch\fcs0 \f31506\fs22\lang1045\langfe1033\cgrid\langnp1045\langfenp1033 \snext0 \sqformat \spriority0 Normal;}{\*\cs10 \additive
|
||||||
|
\ssemihidden \sunhideused \spriority1 Default Paragraph Font;}{\*
|
||||||
\ts11\tsrowd\trftsWidthB3\trpaddl108\trpaddr108\trpaddfl3\trpaddft3\trpaddfb3\trpaddfr3\trcbpat1\trcfpat1\tblind0\tblindtype3\tsvertalt\tsbrdrt\tsbrdrl\tsbrdrb\tsbrdrr\tsbrdrdgl\tsbrdrdgr\tsbrdrh\tsbrdrv \ql \li0\ri0\sa160\sl259\slmult1
|
\ts11\tsrowd\trftsWidthB3\trpaddl108\trpaddr108\trpaddfl3\trpaddft3\trpaddfb3\trpaddfr3\trcbpat1\trcfpat1\tblind0\tblindtype3\tsvertalt\tsbrdrt\tsbrdrl\tsbrdrb\tsbrdrr\tsbrdrdgl\tsbrdrdgr\tsbrdrh\tsbrdrv \ql \li0\ri0\sa160\sl259\slmult1
|
||||||
\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af31506\afs22\alang1025 \ltrch\fcs0 \f31506\fs22\lang1045\langfe1033\cgrid\langnp1045\langfenp1033 \snext11 \ssemihidden \sunhideused Normal Table;}{\*\cs15 \additive
|
\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af31506\afs22\alang1025 \ltrch\fcs0 \f31506\fs22\lang1045\langfe1033\cgrid\langnp1045\langfenp1033 \snext11 \ssemihidden \sunhideused Normal Table;}{\*\cs15 \additive
|
||||||
\rtlch\fcs1 \af0 \ltrch\fcs0 \ul\cf17 \sbasedon10 \sunhideused \styrsid3562894 Hyperlink;}{\*\cs16 \additive \rtlch\fcs1 \af0 \ltrch\fcs0 \ul\cf18 \sbasedon10 \ssemihidden \sunhideused \styrsid7678248 FollowedHyperlink;}}{\*\rsidtbl \rsid1081196
|
\rtlch\fcs1 \af0 \ltrch\fcs0 \ul\cf17 \sbasedon10 \sunhideused \styrsid3562894 Hyperlink;}{\*\cs16 \additive \rtlch\fcs1 \af0 \ltrch\fcs0 \ul\cf18 \sbasedon10 \ssemihidden \sunhideused \styrsid7678248 FollowedHyperlink;}}{\*\rsidtbl \rsid1081196
|
||||||
\rsid3146412\rsid3562894\rsid5731975\rsid7678248\rsid9265883\rsid11107340\rsid12600926\rsid13187577}{\mmathPr\mmathFont34\mbrkBin0\mbrkBinSub0\msmallFrac0\mdispDef1\mlMargin0\mrMargin0\mdefJc1\mwrapIndent1440\mintLim0\mnaryLim1}{\info
|
\rsid3146412\rsid3562894\rsid5731975\rsid7678248\rsid9265883\rsid11107340\rsid11629590\rsid12600926\rsid13187577}{\mmathPr\mmathFont34\mbrkBin0\mbrkBinSub0\msmallFrac0\mdispDef1\mlMargin0\mrMargin0\mdefJc1\mwrapIndent1440\mintLim0\mnaryLim1}{\info
|
||||||
{\author Pawe\'b3 Jastrz\'eabski}{\operator Pawe\'b3 Jastrz\'eabski}{\creatim\yr2013\mo10\dy29\hr15\min17}{\revtim\yr2013\mo10\dy29\hr15\min28}{\version8}{\edmins8}{\nofpages1}{\nofwords33}{\nofchars200}{\nofcharsws232}{\vern57435}}{\*\xmlnstbl {\xmlns1 h
|
{\author Pawe\'b3 Jastrz\'eabski}{\operator Pawe\'b3 Jastrz\'eabski}{\creatim\yr2013\mo10\dy29\hr15\min17}{\revtim\yr2017\mo8\dy20\hr17\min40}{\version9}{\edmins8}{\nofpages1}{\nofwords33}{\nofchars201}{\nofcharsws233}{\vern39}}{\*\xmlnstbl {\xmlns1 http:
|
||||||
ttp://schemas.microsoft.com/office/word/2003/wordml}}\paperw11906\paperh16838\margl1417\margr1417\margt1417\margb1417\gutter0\ltrsect
|
//schemas.microsoft.com/office/word/2003/wordml}}\paperw11906\paperh16838\margl1417\margr1417\margt1417\margb1417\gutter0\ltrsect
|
||||||
\deftab708\widowctrl\ftnbj\aenddoc\hyphhotz425\trackmoves0\trackformatting1\donotembedsysfont1\relyonvml0\donotembedlingdata0\grfdocevents0\validatexml1\showplaceholdtext0\ignoremixedcontent0\saveinvalidxml0
|
\deftab708\widowctrl\ftnbj\aenddoc\hyphhotz425\trackmoves0\trackformatting1\donotembedsysfont1\relyonvml0\donotembedlingdata0\grfdocevents0\validatexml1\showplaceholdtext0\ignoremixedcontent0\saveinvalidxml0
|
||||||
\showxmlerrors1\noxlattoyen\expshrtn\noultrlspc\dntblnsbdb\nospaceforul\formshade\horzdoc\dgmargin\dghspace180\dgvspace180\dghorigin1417\dgvorigin1417\dghshow1\dgvshow1
|
\showxmlerrors1\noxlattoyen\expshrtn\noultrlspc\dntblnsbdb\nospaceforul\formshade\horzdoc\dgmargin\dghspace180\dgvspace180\dghorigin1417\dgvorigin1417\dghshow1\dgvshow1
|
||||||
\jexpand\viewkind1\viewscale100\pgbrdrhead\pgbrdrfoot\splytwnine\ftnlytwnine\htmautsp\nolnhtadjtbl\useltbaln\alntblind\lytcalctblwd\lyttblrtgr\lnbrkrule\nobrkwrptbl\snaptogridincell\allowfieldendsel\wrppunct
|
\jexpand\viewkind1\viewscale100\pgbrdrhead\pgbrdrfoot\splytwnine\ftnlytwnine\htmautsp\nolnhtadjtbl\useltbaln\alntblind\lytcalctblwd\lyttblrtgr\lnbrkrule\nobrkwrptbl\snaptogridincell\allowfieldendsel\wrppunct
|
||||||
@@ -52,12 +54,13 @@ ttp://schemas.microsoft.com/office/word/2003/wordml}}\paperw11906\paperh16838\ma
|
|||||||
\b\fs52\cf6\lang2057\langfe1033\langnp2057\insrsid13187577\charrsid3562894
|
\b\fs52\cf6\lang2057\langfe1033\langnp2057\insrsid13187577\charrsid3562894
|
||||||
\par }{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0 \fs28\lang2057\langfe1033\langnp2057\insrsid1081196 Creation of}{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0 \fs28\lang2057\langfe1033\langnp2057\insrsid3562894\charrsid12600926 }{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0
|
\par }{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0 \fs28\lang2057\langfe1033\langnp2057\insrsid1081196 Creation of}{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0 \fs28\lang2057\langfe1033\langnp2057\insrsid3562894\charrsid12600926 }{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0
|
||||||
\b\fs28\lang2057\langfe1033\langnp2057\insrsid3562894\charrsid12600926 MOBI}{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0 \fs28\lang2057\langfe1033\langnp2057\insrsid3562894\charrsid12600926 files }{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0
|
\b\fs28\lang2057\langfe1033\langnp2057\insrsid3562894\charrsid12600926 MOBI}{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0 \fs28\lang2057\langfe1033\langnp2057\insrsid3562894\charrsid12600926 files }{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0
|
||||||
\fs28\lang2057\langfe1033\langnp2057\insrsid5731975\charrsid12600926 require additional software.}{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0 \fs28\lang2057\langfe1033\langnp2057\insrsid3562894\charrsid12600926
|
\fs28\lang2057\langfe1033\langnp2057\insrsid5731975\charrsid12600926 require}{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0 \fs28\lang2057\langfe1033\langnp2057\insrsid11629590 s}{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0
|
||||||
|
\fs28\lang2057\langfe1033\langnp2057\insrsid5731975\charrsid12600926 additional software.}{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0 \fs28\lang2057\langfe1033\langnp2057\insrsid3562894\charrsid12600926
|
||||||
\par }{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0 \b\fs28\lang2057\langfe1033\langnp2057\insrsid3562894\charrsid12600926 Please download: }{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0\afs24 \ltrch\fcs0
|
\par }{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0 \b\fs28\lang2057\langfe1033\langnp2057\insrsid3562894\charrsid12600926 Please download: }{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0\afs24 \ltrch\fcs0
|
||||||
\b\fs28\lang2057\langfe1033\langnp2057\insrsid3562894\charrsid12600926 HYPERLINK "http://www.amazon.com/gp/feature.html?ie=UTF8&docId=1000765211" }{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0 \b\fs28\lang2057\langfe1033\langnp2057\insrsid3562894\charrsid12600926
|
\b\fs28\lang2057\langfe1033\langnp2057\insrsid3562894\charrsid12600926 HYPERLINK "http://www.amazon.com/gp/feature.html?ie=UTF8&docId=1000765211" }{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0 \b\fs28\lang2057\langfe1033\langnp2057\insrsid3562894\charrsid12600926
|
||||||
{\*\datafield
|
{\*\datafield
|
||||||
00d0c9ea79f9bace118c8200aa004ba90b0200000003000000e0c9ea79f9bace118c8200aa004ba90b9600000068007400740070003a002f002f007700770077002e0061006d0061007a006f006e002e0063006f006d002f00670070002f0066006500610074007500720065002e00680074006d006c003f00690065003d00
|
00d0c9ea79f9bace118c8200aa004ba90b0200000003000000e0c9ea79f9bace118c8200aa004ba90b9600000068007400740070003a002f002f007700770077002e0061006d0061007a006f006e002e0063006f006d002f00670070002f0066006500610074007500720065002e00680074006d006c003f00690065003d00
|
||||||
5500540046003800260064006f006300490064003d0031003000300030003700360035003200310031000000795881f43b1d7f48af2c825dc485276300000000a5ab000000}}}{\fldrslt {\rtlch\fcs1 \af0\afs24 \ltrch\fcs0
|
5500540046003800260064006f006300490064003d0031003000300030003700360035003200310031000000795881f43b1d7f48af2c825dc485276300000000a5ab00000000}}}{\fldrslt {\rtlch\fcs1 \af0\afs24 \ltrch\fcs0
|
||||||
\cs15\b\fs28\ul\cf17\lang2057\langfe1033\langnp2057\insrsid3562894\charrsid12600926 KindleGen}}}\sectd \ltrsect\linex0\headery708\footery708\colsx708\endnhere\sectlinegrid360\sectdefaultcl\sftnbj {\rtlch\fcs1 \af0\afs24 \ltrch\fcs0
|
\cs15\b\fs28\ul\cf17\lang2057\langfe1033\langnp2057\insrsid3562894\charrsid12600926 KindleGen}}}\sectd \ltrsect\linex0\headery708\footery708\colsx708\endnhere\sectlinegrid360\sectdefaultcl\sftnbj {\rtlch\fcs1 \af0\afs24 \ltrch\fcs0
|
||||||
\b\fs28\lang2057\langfe1033\langnp2057\insrsid3562894\charrsid12600926
|
\b\fs28\lang2057\langfe1033\langnp2057\insrsid3562894\charrsid12600926
|
||||||
\par }{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0 \fs28\lang2057\langfe1033\langnp2057\insrsid3562894\charrsid12600926 And place }{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0 \i\fs28\lang2057\langfe1033\langnp2057\insrsid5731975\charrsid12600926 kindlegen.exe}{\rtlch\fcs1
|
\par }{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0 \fs28\lang2057\langfe1033\langnp2057\insrsid3562894\charrsid12600926 And place }{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0 \i\fs28\lang2057\langfe1033\langnp2057\insrsid5731975\charrsid12600926 kindlegen.exe}{\rtlch\fcs1
|
||||||
@@ -119,7 +122,7 @@ d40384e4350d363f2451eced0dae2c082e8761be9969bb979dc9136332de3168aa1a083ae995719a
|
|||||||
617020786d6c6e733a613d22687474703a2f2f736368656d61732e6f70656e786d6c666f726d6174732e6f72672f64726177696e676d6c2f323030362f6d6169
|
617020786d6c6e733a613d22687474703a2f2f736368656d61732e6f70656e786d6c666f726d6174732e6f72672f64726177696e676d6c2f323030362f6d6169
|
||||||
6e22206267313d226c743122207478313d22646b3122206267323d226c743222207478323d22646b322220616363656e74313d22616363656e74312220616363
|
6e22206267313d226c743122207478313d22646b3122206267323d226c743222207478323d22646b322220616363656e74313d22616363656e74312220616363
|
||||||
656e74323d22616363656e74322220616363656e74333d22616363656e74332220616363656e74343d22616363656e74342220616363656e74353d22616363656e74352220616363656e74363d22616363656e74362220686c696e6b3d22686c696e6b2220666f6c486c696e6b3d22666f6c486c696e6b222f3e}
|
656e74323d22616363656e74322220616363656e74333d22616363656e74332220616363656e74343d22616363656e74342220616363656e74353d22616363656e74352220616363656e74363d22616363656e74362220686c696e6b3d22686c696e6b2220666f6c486c696e6b3d22666f6c486c696e6b222f3e}
|
||||||
{\*\latentstyles\lsdstimax371\lsdlockeddef0\lsdsemihiddendef0\lsdunhideuseddef0\lsdqformatdef0\lsdprioritydef99{\lsdlockedexcept \lsdqformat1 \lsdpriority0 \lsdlocked0 Normal;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 1;
|
{\*\latentstyles\lsdstimax375\lsdlockeddef0\lsdsemihiddendef0\lsdunhideuseddef0\lsdqformatdef0\lsdprioritydef99{\lsdlockedexcept \lsdqformat1 \lsdpriority0 \lsdlocked0 Normal;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 1;
|
||||||
\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 2;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 3;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 4;
|
\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 2;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 3;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 4;
|
||||||
\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 5;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 6;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 7;
|
\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 5;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 6;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 7;
|
||||||
\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 8;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 9;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 1;
|
\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 8;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 9;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 1;
|
||||||
@@ -196,7 +199,8 @@ d40384e4350d363f2451eced0dae2c082e8761be9969bb979dc9136332de3168aa1a083ae995719a
|
|||||||
\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 4;\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 5;\lsdpriority47 \lsdlocked0 List Table 2 Accent 5;\lsdpriority48 \lsdlocked0 List Table 3 Accent 5;
|
\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 4;\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 5;\lsdpriority47 \lsdlocked0 List Table 2 Accent 5;\lsdpriority48 \lsdlocked0 List Table 3 Accent 5;
|
||||||
\lsdpriority49 \lsdlocked0 List Table 4 Accent 5;\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 5;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 5;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 5;
|
\lsdpriority49 \lsdlocked0 List Table 4 Accent 5;\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 5;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 5;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 5;
|
||||||
\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 6;\lsdpriority47 \lsdlocked0 List Table 2 Accent 6;\lsdpriority48 \lsdlocked0 List Table 3 Accent 6;\lsdpriority49 \lsdlocked0 List Table 4 Accent 6;
|
\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 6;\lsdpriority47 \lsdlocked0 List Table 2 Accent 6;\lsdpriority48 \lsdlocked0 List Table 3 Accent 6;\lsdpriority49 \lsdlocked0 List Table 4 Accent 6;
|
||||||
\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 6;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 6;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 6;}}{\*\datastore 010500000200000018000000
|
\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 6;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 6;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 6;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Mention;
|
||||||
|
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Smart Hyperlink;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Hashtag;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Unresolved Mention;}}{\*\datastore 010500000200000018000000
|
||||||
4d73786d6c322e534158584d4c5265616465722e362e30000000000000000000000e0000
|
4d73786d6c322e534158584d4c5265616465722e362e30000000000000000000000e0000
|
||||||
d0cf11e0a1b11ae1000000000000000000000000000000003e000300feff0900060000000000000000000000010000000100000000000000001000000200000001000000feffffff0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
d0cf11e0a1b11ae1000000000000000000000000000000003e000300feff0900060000000000000000000000010000000100000000000000001000000200000001000000feffffff0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||||
@@ -206,24 +210,24 @@ fffffffffffffffffdffffff04000000feffffff05000000fefffffffeffffffffffffffffffffff
|
|||||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||||
ffffffffffffffffffffffffffffffff52006f006f007400200045006e00740072007900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000500ffffffffffffffff010000000c6ad98892f1d411a65f0040963251e50000000000000000000000006069
|
ffffffffffffffffffffffffffffffff52006f006f007400200045006e00740072007900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000500ffffffffffffffff010000000c6ad98892f1d411a65f0040963251e5000000000000000000000000b00f
|
||||||
e214b3d4ce010300000080020000000000004d0073006f004400610074006100530074006f0072006500000000000000000000000000000000000000000000000000000000000000000000000000000000001a000101ffffffffffffffff0200000000000000000000000000000000000000000000006069e214b3d4ce01
|
9da8ca19d30103000000c0020000000000004d0073006f004400610074006100530074006f0072006500000000000000000000000000000000000000000000000000000000000000000000000000000000001a000101ffffffffffffffff020000000000000000000000000000000000000000000000b00f9da8ca19d301
|
||||||
6069e214b3d4ce010000000000000000000000003500d900ca00dd00ce004400cc00c8005a0045004700c400cd0057004900c500d400c900cb00ce00570051003d003d000000000000000000000000000000000032000101ffffffffffffffff0300000000000000000000000000000000000000000000006069e214b3d4
|
b00f9da8ca19d301000000000000000000000000ca0041004300c300d300d300c70058004d00d4003000c9004d00c200590043003100320055004a00300051003d003d000000000000000000000000000000000032000101ffffffffffffffff030000000000000000000000000000000000000000000000b00f9da8ca19
|
||||||
ce016069e214b3d4ce010000000000000000000000004900740065006d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000201ffffffff04000000ffffffff000000000000000000000000000000000000000000000000
|
d301b00f9da8ca19d3010000000000000000000000004900740065006d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000201ffffffff04000000ffffffff000000000000000000000000000000000000000000000000
|
||||||
00000000000000000000000000000000fc00000000000000010000000200000003000000feffffff0500000006000000070000000800000009000000feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
00000000000000000000000000000000320100000000000001000000020000000300000004000000feffffff060000000700000008000000090000000a000000feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3c623a536f75726365732053656c65637465645374796c653d225c415041536978746845646974696f6e4f66666963654f6e6c696e652e78736c22205374796c654e616d653d22415041222056657273696f6e3d22362220786d6c6e733a
|
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d225554462d3822207374616e64616c6f6e653d226e6f223f3e3c623a536f75726365732053656c65637465645374796c653d225c41504153697874684564697469
|
||||||
623d22687474703a2f2f736368656d61732e6f70656e786d6c666f726d6174732e6f72672f6f6666696365446f63756d656e742f323030362f6269626c696f6772617068792220786d6c6e733d22687474703a2f2f736368656d61732e6f70656e786d6c666f726d6174732e6f72672f6f6666696365446f63756d656e74
|
6f6e4f66666963654f6e6c696e652e78736c22205374796c654e616d653d22415041222056657273696f6e3d22362220786d6c6e733a623d22687474703a2f2f736368656d61732e6f70656e786d6c666f726d6174732e6f72672f6f6666696365446f63756d656e742f323030362f6269626c696f677261706879222078
|
||||||
2f323030362f6269626c696f677261706879223e3c2f623a536f75726365733e000000003c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d225554462d3822207374616e64616c6f6e653d226e6f223f3e0d0a3c64733a6461746173746f72654974656d2064733a6974656d49443d227b42384244
|
6d6c6e733d22687474703a2f2f736368656d61732e6f70656e786d6c666f726d6174732e6f72672f6f6666696365446f63756d656e742f323030362f6269626c696f677261706879223e3c2f623a536f75726365733e00000000000000000000000000003c3f786d6c2076657273696f6e3d22312e302220656e636f6469
|
||||||
394137462d323833422d343136342d413442352d3632323544323941454535397d2220786d6c6e733a64733d22687474703a2f2f736368656d61732e6f70656e786d6c666f726d6174732e6f72672f6f6666696365446f63756d656e742f323030362f637573746f6d586d6c223e3c64733a736368656d61526566733e3c
|
6e673d225554462d3822207374616e64616c6f6e653d226e6f223f3e0d0a3c64733a6461746173746f72654974656d2064733a6974656d49443d227b43464133303041382d443733392d343633332d413933322d3236303236444335303936397d2220786d6c6e733a64733d22687474703a2f2f736368656d61732e6f70
|
||||||
64733a736368656d615265662064733a7572693d22687474703a2f2f736368656d61732e6f70656e500072006f007000650072007400690065007300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000200ffffffffffffffffffffffff000000000000
|
656e786d6c666f726d6174732e6f72672f6f6666696365446f63756d656e742f323030362f637573500072006f007000650072007400690065007300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000200ffffffffffffffffffffffff000000000000
|
||||||
0000000000000000000000000000000000000000000000000000000000000400000055010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff00000000
|
0000000000000000000000000000000000000000000000000000000000000500000055010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff00000000
|
||||||
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff0000
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff0000
|
||||||
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff
|
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff
|
||||||
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000786d6c666f726d6174732e6f72672f6f6666696365446f63756d656e742f323030362f6269626c696f677261706879222f3e3c2f64733a736368656d61526566733e3c2f64733a6461746173746f
|
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000746f6d586d6c223e3c64733a736368656d61526566733e3c64733a736368656d615265662064733a7572693d22687474703a2f2f736368656d61732e6f70656e786d6c666f726d6174732e6f7267
|
||||||
72654974656d3e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
2f6f6666696365446f63756d656e742f323030362f6269626c696f677261706879222f3e3c2f64733a736368656d61526566733e3c2f64733a6461746173746f72654974656d3e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000105000000000000}}
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000105000000000000}}
|
||||||
3
other/windows/sentry.py.enc
Normal file
3
other/windows/sentry.py.enc
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
éd¼7¶ÍÑ<>ßñ|l“z6¯n¸I_œ—Åž:£ê-ˆ!ën‚BCDÇ}fðzIe|¦ÜÖà\9KW°f½H[íY¶LYô7^Ï@mª*<2A>YmÎ_z`3©WSD{Ö"áˆa@>®;}\¥—,D›š˜Ý·Ý!yX<79>±è–<C3A8>¯~ÿ~Y_æxdÕï BøŠT
|
||||||
|
B”𢯣
|
||||||
|
uô|91u~¿Pa¸¸LDÜjh
|
||||||
Binary file not shown.
5
requirements.txt
Normal file
5
requirements.txt
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
PyQt5>=5.6.0
|
||||||
|
Pillow>=4.0.0
|
||||||
|
psutil>=5.0.0
|
||||||
|
python-slugify>=1.2.1
|
||||||
|
raven>=6.0.0
|
||||||
135
setup.py
135
setup.py
@@ -2,11 +2,11 @@
|
|||||||
"""
|
"""
|
||||||
pip/pyinstaller build script for KCC.
|
pip/pyinstaller build script for KCC.
|
||||||
|
|
||||||
Usage (Windows):
|
Install as Python package:
|
||||||
py -3 setup.py build_binary
|
python3 setup.py install
|
||||||
|
|
||||||
Usage (Linux/OS X):
|
Create EXE/APP/DEB:
|
||||||
python3 setup.py build_binary or python3 setup.py build_binary --pyz
|
python3 setup.py build_binary
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
@@ -14,34 +14,28 @@ import sys
|
|||||||
import shutil
|
import shutil
|
||||||
import setuptools
|
import setuptools
|
||||||
import distutils.cmd
|
import distutils.cmd
|
||||||
from distutils.command.build import build
|
|
||||||
from kindlecomicconverter import __version__
|
from kindlecomicconverter import __version__
|
||||||
|
|
||||||
NAME = 'KindleComicConverter'
|
NAME = 'KindleComicConverter'
|
||||||
MAIN = 'kcc.py'
|
MAIN = 'kcc.py'
|
||||||
VERSION = __version__
|
VERSION = __version__
|
||||||
OPTIONS = {}
|
|
||||||
|
|
||||||
|
|
||||||
class BuildBinaryCommand(distutils.cmd.Command):
|
class BuildBinaryCommand(distutils.cmd.Command):
|
||||||
description = 'build binary release'
|
description = 'build binary release'
|
||||||
user_options = [
|
user_options = []
|
||||||
('pyz', None, 'build PYZ package'),
|
|
||||||
]
|
|
||||||
|
|
||||||
def initialize_options(self):
|
def initialize_options(self):
|
||||||
# noinspection PyAttributeOutsideInit
|
pass
|
||||||
self.pyz = False
|
|
||||||
|
|
||||||
def finalize_options(self):
|
def finalize_options(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# noinspection PyShadowingNames
|
||||||
def run(self):
|
def run(self):
|
||||||
|
VERSION = __version__
|
||||||
if sys.platform == 'darwin':
|
if sys.platform == 'darwin':
|
||||||
if os.path.isfile('Kindle Comic Converter.spec'):
|
os.system('pyinstaller -y -F -i icons/comic2ebook.icns -n "Kindle Comic Converter" -w -s kcc.py')
|
||||||
os.system('pyinstaller "Kindle Comic Converter.spec"')
|
|
||||||
else:
|
|
||||||
os.system('pyinstaller -y -F -i icons/comic2ebook.icns -n "Kindle Comic Converter" -w -s --noupx kcc.py')
|
|
||||||
shutil.copy('other/osx/7za', 'dist/Kindle Comic Converter.app/Contents/Resources')
|
shutil.copy('other/osx/7za', 'dist/Kindle Comic Converter.app/Contents/Resources')
|
||||||
shutil.copy('other/osx/unrar', 'dist/Kindle Comic Converter.app/Contents/Resources')
|
shutil.copy('other/osx/unrar', 'dist/Kindle Comic Converter.app/Contents/Resources')
|
||||||
shutil.copy('other/osx/Info.plist', 'dist/Kindle Comic Converter.app/Contents')
|
shutil.copy('other/osx/Info.plist', 'dist/Kindle Comic Converter.app/Contents')
|
||||||
@@ -49,87 +43,34 @@ class BuildBinaryCommand(distutils.cmd.Command):
|
|||||||
shutil.copy('other/windows/Additional-LICENSE.txt', 'dist/Kindle Comic Converter.app/Contents/Resources')
|
shutil.copy('other/windows/Additional-LICENSE.txt', 'dist/Kindle Comic Converter.app/Contents/Resources')
|
||||||
os.chmod('dist/Kindle Comic Converter.app/Contents/Resources/unrar', 0o777)
|
os.chmod('dist/Kindle Comic Converter.app/Contents/Resources/unrar', 0o777)
|
||||||
os.chmod('dist/Kindle Comic Converter.app/Contents/Resources/7za', 0o777)
|
os.chmod('dist/Kindle Comic Converter.app/Contents/Resources/7za', 0o777)
|
||||||
if os.path.isfile('setup.sh'):
|
|
||||||
os.system('./setup.sh')
|
|
||||||
os.system('appdmg kcc.json dist/KindleComicConverter_osx_' + VERSION + '.dmg')
|
os.system('appdmg kcc.json dist/KindleComicConverter_osx_' + VERSION + '.dmg')
|
||||||
exit(0)
|
exit(0)
|
||||||
elif sys.platform == 'win32':
|
elif sys.platform == 'win32':
|
||||||
if os.path.isfile('KCC.spec'):
|
os.system('pyinstaller -y -F -i icons\comic2ebook.ico -n KCC -w --noupx kcc.py')
|
||||||
os.system('pyinstaller KCC.spec')
|
|
||||||
else:
|
|
||||||
os.system('pyinstaller -y -F -i icons\comic2ebook.ico -n KCC -w --noupx kcc.py')
|
|
||||||
if os.path.isfile('setup.bat'):
|
|
||||||
os.system('setup.bat')
|
|
||||||
exit(0)
|
exit(0)
|
||||||
else:
|
else:
|
||||||
if self.pyz:
|
os.system('pyinstaller -y -F kcc.py')
|
||||||
script = '''
|
os.system('mkdir -p dist/usr/bin dist/usr/share/applications dist/usr/share/doc/kindlecomicconverter '
|
||||||
cp kcc.py __main__.py
|
'dist/usr/share/kindlecomicconverter dist/usr/share/lintian/overrides')
|
||||||
zip kcc.zip __main__.py kindlecomicconverter/*.py
|
os.system('mv dist/kcc dist/usr/bin')
|
||||||
echo "#!/usr/bin/env python3" > kcc-bin
|
os.system('cp icons/comic2ebook.png dist/usr/share/kindlecomicconverter')
|
||||||
cat kcc.zip >> kcc-bin
|
os.system('cp LICENSE.txt dist/usr/share/doc/kindlecomicconverter/copyright')
|
||||||
chmod +x kcc-bin
|
os.system('cp other/linux/kindlecomicconverter.desktop dist/usr/share/applications')
|
||||||
|
os.system('cp other/linux/kindlecomicconverter dist/usr/share/lintian/overrides')
|
||||||
cp kcc-c2e.py __main__.py
|
os.chdir('dist')
|
||||||
zip kcc-c2e.zip __main__.py kindlecomicconverter/*.py
|
os.system('fpm -f -s dir -t deb -n kindlecomicconverter -v ' + VERSION +
|
||||||
echo "#!/usr/bin/env python3" > kcc-c2e-bin
|
' -m "Paweł Jastrzębski <pawelj@iosphe.re>" --license "ISC" '
|
||||||
cat kcc-c2e.zip >> kcc-c2e-bin
|
'--description "$(printf "Comic and Manga converter for e-book '
|
||||||
chmod +x kcc-c2e-bin
|
'readers.\nThis app allows you to transform your PNG, JPG, GIF, '
|
||||||
|
'CBZ, CBR and CB7 files\ninto EPUB or MOBI format e-books.")" '
|
||||||
cp kcc-c2p.py __main__.py
|
'--url "https://kcc.iosphe.re/" --deb-priority "optional" --vendor "" '
|
||||||
zip kcc-c2p.zip __main__.py kindlecomicconverter/*.py
|
'--category "graphics" -d "unrar | unrar-free" -d "p7zip-full" -d "libc6" usr')
|
||||||
echo "#!/usr/bin/env python3" > kcc-c2p-bin
|
exit(0)
|
||||||
cat kcc-c2p.zip >> kcc-c2p-bin
|
|
||||||
chmod +x kcc-c2p-bin
|
|
||||||
|
|
||||||
mkdir dist
|
|
||||||
tar --xform s:^.*/:: \
|
|
||||||
--xform s/LICENSE.txt/LICENSE/ \
|
|
||||||
--xform s/kcc-bin/kcc/ \
|
|
||||||
--xform s/kcc-c2p-bin/kcc-c2p/ \
|
|
||||||
--xform s/kcc-c2e-bin/kcc-c2e/ \
|
|
||||||
--xform s/comic2ebook/kcc/ \
|
|
||||||
-czf dist/KindleComicConverter_linux_''' + VERSION + '''.tar.gz \
|
|
||||||
kcc-bin kcc-c2e-bin kcc-c2p-bin LICENSE.txt README.md icons/comic2ebook.png
|
|
||||||
rm __main__.py kcc.zip kcc-c2e.zip kcc-c2p.zip kcc-bin kcc-c2e-bin kcc-c2p-bin
|
|
||||||
'''
|
|
||||||
os.system("bash -c '%s'" % script)
|
|
||||||
exit(0)
|
|
||||||
else:
|
|
||||||
os.system('docker run --rm -v ' + os.getcwd() + ':/app -e KCCVER=' + VERSION + ' acidweb/kcc')
|
|
||||||
exit(0)
|
|
||||||
|
|
||||||
|
|
||||||
class BuildCommand(build):
|
|
||||||
def run(self):
|
|
||||||
os.makedirs('build/_scripts/', exist_ok=True)
|
|
||||||
shutil.copyfile('kcc.py', 'build/_scripts/kcc')
|
|
||||||
shutil.copyfile('kcc-c2e.py', 'build/_scripts/kcc-c2e')
|
|
||||||
shutil.copyfile('kcc-c2p.py', 'build/_scripts/kcc-c2p')
|
|
||||||
# noinspection PyShadowingNames
|
|
||||||
OPTIONS = dict(
|
|
||||||
scripts=['build/_scripts/kcc',
|
|
||||||
'build/_scripts/kcc-c2e',
|
|
||||||
'build/_scripts/kcc-c2p'],
|
|
||||||
packages=['kcc'],
|
|
||||||
install_requires=[
|
|
||||||
'PyQt5>=5.6.0'
|
|
||||||
'Pillow>=3.2.0',
|
|
||||||
'psutil>=4.1.0',
|
|
||||||
'python-slugify>=1.2.0',
|
|
||||||
'raven>=5.13.0',
|
|
||||||
],
|
|
||||||
zip_safe=False,
|
|
||||||
)
|
|
||||||
if sys.version_info[1] < 5:
|
|
||||||
OPTIONS['install_requires'].append('scandir>=1.2.0')
|
|
||||||
build.run(self)
|
|
||||||
|
|
||||||
|
|
||||||
setuptools.setup(
|
setuptools.setup(
|
||||||
cmdclass={
|
cmdclass={
|
||||||
'build_binary': BuildBinaryCommand,
|
'build_binary': BuildBinaryCommand,
|
||||||
'build': BuildCommand,
|
|
||||||
},
|
},
|
||||||
name=NAME,
|
name=NAME,
|
||||||
version=VERSION,
|
version=VERSION,
|
||||||
@@ -137,7 +78,25 @@ setuptools.setup(
|
|||||||
author_email='ciromattia@gmail.com, pawelj@iosphe.re',
|
author_email='ciromattia@gmail.com, pawelj@iosphe.re',
|
||||||
description='Comic and Manga converter for e-book readers.',
|
description='Comic and Manga converter for e-book readers.',
|
||||||
license='ISC License (ISCL)',
|
license='ISC License (ISCL)',
|
||||||
keywords='kindle comic mobipocket mobi cbz cbr manga',
|
keywords=['kindle', 'kobo', 'comic', 'manga', 'mobi', 'epub', 'cbz'],
|
||||||
url='http://github.com/ciromattia/kcc',
|
url='http://github.com/ciromattia/kcc',
|
||||||
**OPTIONS
|
entry_points={
|
||||||
|
'console_scripts': [
|
||||||
|
'kcc-c2e = kindlecomicconverter.startup:startC2E',
|
||||||
|
'kcc-c2p = kindlecomicconverter.startup:startC2P',
|
||||||
|
],
|
||||||
|
'gui_scripts': [
|
||||||
|
'kcc = kindlecomicconverter.startup:start',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
packages=['kindlecomicconverter'],
|
||||||
|
install_requires=[
|
||||||
|
'PyQt5>=5.6.0',
|
||||||
|
'Pillow>=4.0.0',
|
||||||
|
'psutil>=5.0.0',
|
||||||
|
'python-slugify>=1.2.1',
|
||||||
|
'raven>=6.0.0',
|
||||||
|
],
|
||||||
|
classifiers=[],
|
||||||
|
zip_safe=False,
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user