mirror of
https://github.com/ciromattia/kcc
synced 2026-04-15 13:38:46 +00:00
Compare commits
48 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
85c1801417 | ||
|
|
b28ee08d01 | ||
|
|
dba927c351 | ||
|
|
dd5fd621db | ||
|
|
21a167b3ee | ||
|
|
1c9eeee52d | ||
|
|
611ee31526 | ||
|
|
7c4fdf9d1a | ||
|
|
b14f59e77a | ||
|
|
b4ec0b4a74 | ||
|
|
a90b4c82c5 | ||
|
|
390d58bf08 | ||
|
|
e1aa6cd0af | ||
|
|
718fda2f0c | ||
|
|
9d7904f63b | ||
|
|
ec58964c7c | ||
|
|
0b687ebadc | ||
|
|
9bc1f92c8c | ||
|
|
56f6c6962f | ||
|
|
dfd15ab572 | ||
|
|
5588ad9250 | ||
|
|
0c2adb517e | ||
|
|
9ab1cd359c | ||
|
|
41d24e77e1 | ||
|
|
17206ddf8b | ||
|
|
896c05a72f | ||
|
|
f83106f35b | ||
|
|
dfca136a2d | ||
|
|
92ced5f415 | ||
|
|
d18275d525 | ||
|
|
c049adc3a1 | ||
|
|
a3ce26983e | ||
|
|
fe8195cfed | ||
|
|
3a1737e8d0 | ||
|
|
fb0c0231f3 | ||
|
|
2e807e23e1 | ||
|
|
27841abb83 | ||
|
|
b71d056559 | ||
|
|
a822dfa3ae | ||
|
|
70de379987 | ||
|
|
16e275bb1f | ||
|
|
b225de7b97 | ||
|
|
4a89446914 | ||
|
|
64521de577 | ||
|
|
38b14fd734 | ||
|
|
4fa72780a1 | ||
|
|
c979486e28 | ||
|
|
03bd67cf2f |
21
.github/workflows/package-linux.yml
vendored
21
.github/workflows/package-linux.yml
vendored
@@ -7,7 +7,7 @@ on:
|
||||
push:
|
||||
tags:
|
||||
- "v*.*.*"
|
||||
|
||||
|
||||
# Don't trigger if it's just a documentation update
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
@@ -23,9 +23,9 @@ on:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
@@ -34,18 +34,13 @@ jobs:
|
||||
- name: Install python dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y libpng-dev libjpeg-dev p7zip-full python3-pyqt5 squashfs-tools
|
||||
python -m pip install --upgrade pip setuptools wheel pyinstaller
|
||||
pip install -r requirements.txt
|
||||
sudo apt-get install -y libpng-dev libjpeg-dev p7zip-full python3-pyqt5 python3-pip squashfs-tools libfuse2
|
||||
python -m pip install --upgrade pip setuptools wheel certifi pyinstaller PyQt6 --no-binary pyinstaller
|
||||
python -m pip install -r requirements.txt
|
||||
- name: build binary
|
||||
run: |
|
||||
python setup.py build_binary
|
||||
chmod +x dist/kcc_linux*
|
||||
- name: upload build
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: linux-build
|
||||
path: dist/kcc_linux*
|
||||
# issue with this action, disabled and commented out
|
||||
# see https://github.com/AppImageCrafters/build-appimage/issues/5
|
||||
# see https://appimage-builder.readthedocs.io/en/latest/intro/install.html#install-appimagetool
|
||||
@@ -63,9 +58,8 @@ jobs:
|
||||
appimage-builder --recipe AppImageBuilder.yml --skip-test
|
||||
env:
|
||||
UPDATE_INFO: gh-releases-zsync|ciromattia|kcc|latest|*x86_64.AppImage.zsync
|
||||
|
||||
- name: upload artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: AppImage
|
||||
path: './*.AppImage*'
|
||||
@@ -78,5 +72,4 @@ jobs:
|
||||
files: |
|
||||
CHANGELOG.md
|
||||
LICENSE.txt
|
||||
dist/kcc_linux*
|
||||
*.AppImage*
|
||||
|
||||
45
.github/workflows/package-macos.yml
vendored
45
.github/workflows/package-macos.yml
vendored
@@ -25,7 +25,7 @@ jobs:
|
||||
build:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
@@ -33,13 +33,45 @@ jobs:
|
||||
cache: 'pip'
|
||||
- name: Install python dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip setuptools wheel pyinstaller
|
||||
python -m pip install --upgrade pip setuptools wheel pyinstaller certifi
|
||||
pip install -r requirements.txt
|
||||
- name: Install the Apple certificate and provisioning profile
|
||||
# TODO signing
|
||||
# https://federicoterzi.com/blog/automatic-code-signing-and-notarization-for-macos-apps-using-github-actions/
|
||||
if: ${{ false }}
|
||||
env:
|
||||
BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }}
|
||||
P12_PASSWORD: ${{ secrets.P12_PASSWORD }}
|
||||
BUILD_PROVISION_PROFILE_BASE64: ${{ secrets.BUILD_PROVISION_PROFILE_BASE64 }}
|
||||
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
|
||||
run: |
|
||||
# create variables
|
||||
CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12
|
||||
PP_PATH=$RUNNER_TEMP/build_pp.mobileprovision
|
||||
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
|
||||
|
||||
# import certificate and provisioning profile from secrets
|
||||
echo -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode -o $CERTIFICATE_PATH
|
||||
echo -n "$BUILD_PROVISION_PROFILE_BASE64" | base64 --decode -o $PP_PATH
|
||||
|
||||
# create temporary keychain
|
||||
security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
|
||||
security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
|
||||
security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
|
||||
|
||||
# import certificate to keychain
|
||||
security import $CERTIFICATE_PATH -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
|
||||
security list-keychain -d user -s $KEYCHAIN_PATH
|
||||
|
||||
# apply provisioning profile
|
||||
mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
|
||||
cp $PP_PATH ~/Library/MobileDevice/Provisioning\ Profiles
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
- run: npm install -g appdmg
|
||||
- name: build binary
|
||||
# TODO /usr/bin/codesign --force -s "$MACOS_CERTIFICATE_NAME" --options runtime dist/Applications/Kindle\ Comic\ Converter.app -v
|
||||
run: |
|
||||
python setup.py build_binary
|
||||
- name: upload build
|
||||
@@ -56,4 +88,11 @@ jobs:
|
||||
files: |
|
||||
CHANGELOG.md
|
||||
LICENSE.txt
|
||||
dist/*.dmg
|
||||
dist/*.dmg
|
||||
- name: Clean up keychain and provisioning profile
|
||||
# TODO signing
|
||||
if: ${{ false }}
|
||||
# if: ${{ always() }}
|
||||
run: |
|
||||
security delete-keychain $RUNNER_TEMP/app-signing.keychain-db
|
||||
rm ~/Library/MobileDevice/Provisioning\ Profiles/build_pp.mobileprovision
|
||||
63
.github/workflows/package-windows-with-docker.yml
vendored
Normal file
63
.github/workflows/package-windows-with-docker.yml
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
|
||||
|
||||
name: build KCC for windows with docker
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
tags:
|
||||
- "v*.*.*"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
# - name: Set up Python
|
||||
# uses: actions/setup-python@v4
|
||||
# with:
|
||||
# python-version: 3.11
|
||||
# cache: 'pip'
|
||||
# - name: Install python dependencies
|
||||
# run: |
|
||||
# python -m pip install --upgrade pip setuptools wheel pyinstaller
|
||||
# pip install -r requirements.txt
|
||||
# - name: build binary
|
||||
# run: |
|
||||
# pyi-makespec -F -i icons\\comic2ebook.ico -n KCC_test -w --noupx kcc.py
|
||||
- name: Package Application
|
||||
uses: JackMcKew/pyinstaller-action-windows@main
|
||||
with:
|
||||
path: .
|
||||
spec: ./kcc.spec
|
||||
- name: Package Application
|
||||
uses: JackMcKew/pyinstaller-action-windows@main
|
||||
with:
|
||||
path: .
|
||||
spec: ./kcc-c2e.spec
|
||||
- name: Package Application
|
||||
uses: JackMcKew/pyinstaller-action-windows@main
|
||||
with:
|
||||
path: .
|
||||
spec: ./kcc-c2p.spec
|
||||
- name: rename binaries
|
||||
run: |
|
||||
version_built=$(cat kindlecomicconverter/__init__.py | grep version | awk '{print $3}' | sed "s/[^.0-9b]//g")
|
||||
mv dist/windows/kcc.exe dist/windows/kcc_${version_built}.exe
|
||||
mv dist/windows/kcc-c2e.exe dist/windows/kcc-c2e_${version_built}.exe
|
||||
mv dist/windows/kcc-c2p.exe dist/windows/kcc-c2p_${version_built}.exe
|
||||
- name: upload build
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: windows-build
|
||||
path: dist/windows/*.exe
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
with:
|
||||
prerelease: true
|
||||
generate_release_notes: true
|
||||
files: |
|
||||
CHANGELOG.md
|
||||
LICENSE.txt
|
||||
dist/windows/*.exe
|
||||
9
.github/workflows/package-windows.yml
vendored
9
.github/workflows/package-windows.yml
vendored
@@ -25,16 +25,19 @@ jobs:
|
||||
build:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.11
|
||||
cache: 'pip'
|
||||
- name: Install python dependencies
|
||||
- name: Install dependencies
|
||||
env:
|
||||
PYINSTALLER_COMPILE_BOOTLOADER: 1
|
||||
run: |
|
||||
python -m pip install --upgrade pip setuptools wheel pyinstaller
|
||||
python -m pip install --upgrade pip setuptools wheel
|
||||
pip install -r requirements.txt
|
||||
pip install certifi pyinstaller --no-binary pyinstaller
|
||||
- name: build binary
|
||||
run: |
|
||||
python setup.py build_binary
|
||||
|
||||
50
.github/workflows/python-package-test.yml
vendored
50
.github/workflows/python-package-test.yml
vendored
@@ -1,50 +0,0 @@
|
||||
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
|
||||
|
||||
name: Publish Python distributions to TestPyPI
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*.*.*"
|
||||
|
||||
# Don't trigger if it's just a documentation update
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
- '**.MD'
|
||||
- '**.yml'
|
||||
- '**.sh'
|
||||
- 'docs/**'
|
||||
- 'Dockerfile'
|
||||
- 'LICENSE'
|
||||
- '.gitattributes'
|
||||
- '.gitignore'
|
||||
- '.dockerignore'
|
||||
|
||||
jobs:
|
||||
release:
|
||||
if: github.repository == 'darodi/kcc'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.11
|
||||
cache: 'pip'
|
||||
- name: Install python dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip setuptools wheel pyinstaller
|
||||
pip install -r requirements.txt
|
||||
- name: Build Dist
|
||||
run: |
|
||||
sed -i "s#NAME = 'KindleComicConverter'#NAME = 'KindleComicConverterDarodi'#" setup.py
|
||||
python setup.py sdist
|
||||
- name: Release On TestPyPI
|
||||
uses: pypa/gh-action-pypi-publish@release/v1
|
||||
with:
|
||||
user: __token__
|
||||
password: ${{ secrets.TEST_PYPI_API_TOKEN }}
|
||||
repository_url: https://test.pypi.org/legacy/
|
||||
skip_existing: true
|
||||
verbose: true
|
||||
print_hash: true
|
||||
44
.github/workflows/python-package.yml
vendored
44
.github/workflows/python-package.yml
vendored
@@ -1,44 +0,0 @@
|
||||
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
|
||||
|
||||
name: Publish Python distributions to PyPI
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*.*.*"
|
||||
|
||||
# Don't trigger if it's just a documentation update
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
- '**.MD'
|
||||
- '**.yml'
|
||||
- '**.sh'
|
||||
- 'docs/**'
|
||||
- 'Dockerfile'
|
||||
- 'LICENSE'
|
||||
- '.gitattributes'
|
||||
- '.gitignore'
|
||||
- '.dockerignore'
|
||||
|
||||
jobs:
|
||||
release:
|
||||
if: github.repository == 'ciromattia/kcc'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.11
|
||||
cache: 'pip'
|
||||
- name: Install python dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip setuptools wheel pyinstaller
|
||||
pip install -r requirements.txt
|
||||
- name: Build Dist
|
||||
run: |
|
||||
python setup.py sdist
|
||||
- name: Publish a Python distribution to PyPI
|
||||
uses: pypa/gh-action-pypi-publish@release/v1
|
||||
with:
|
||||
password: ${{ secrets.PYPI_API_TOKEN }}
|
||||
@@ -19,24 +19,21 @@ AppDir:
|
||||
- amd64
|
||||
allow_unauthenticated: true
|
||||
sources:
|
||||
- sourceline: deb http://archive.ubuntu.com/ubuntu focal main restricted
|
||||
- sourceline: deb http://archive.ubuntu.com/ubuntu focal-updates main restricted
|
||||
- sourceline: deb http://archive.ubuntu.com/ubuntu focal universe
|
||||
- sourceline: deb http://archive.ubuntu.com/ubuntu focal-updates universe
|
||||
- sourceline: deb http://archive.ubuntu.com/ubuntu focal multiverse
|
||||
- sourceline: deb http://archive.ubuntu.com/ubuntu focal-updates multiverse
|
||||
- sourceline: deb http://archive.ubuntu.com/ubuntu focal-backports main restricted
|
||||
- sourceline: deb http://archive.ubuntu.com/ubuntu jammy main restricted
|
||||
- sourceline: deb http://archive.ubuntu.com/ubuntu jammy-updates main restricted
|
||||
- sourceline: deb http://archive.ubuntu.com/ubuntu jammy universe
|
||||
- sourceline: deb http://archive.ubuntu.com/ubuntu jammy-updates universe
|
||||
- sourceline: deb http://archive.ubuntu.com/ubuntu jammy multiverse
|
||||
- sourceline: deb http://archive.ubuntu.com/ubuntu jammy-updates multiverse
|
||||
- sourceline: deb http://archive.ubuntu.com/ubuntu jammy-backports main restricted
|
||||
universe multiverse
|
||||
- sourceline: deb http://security.ubuntu.com/ubuntu focal-security main restricted
|
||||
- sourceline: deb http://security.ubuntu.com/ubuntu focal-security universe
|
||||
- sourceline: deb http://security.ubuntu.com/ubuntu focal-security multiverse
|
||||
- sourceline: deb http://security.ubuntu.com/ubuntu jammy-security main restricted
|
||||
- sourceline: deb http://security.ubuntu.com/ubuntu jammy-security universe
|
||||
- sourceline: deb http://security.ubuntu.com/ubuntu jammy-security multiverse
|
||||
include:
|
||||
- zlib1g:amd64
|
||||
- libc6:amd64
|
||||
files:
|
||||
include:
|
||||
- /lib/x86_64-linux-gnu/libGLX.so.0
|
||||
- /lib/x86_64-linux-gnu/libGLdispatch.so.0
|
||||
- /usr/lib/locale/locale-archive
|
||||
include: []
|
||||
exclude:
|
||||
- usr/share/man
|
||||
- usr/share/doc/*/README.*
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# CHANGELOG
|
||||
|
||||
#### 5.6.1:
|
||||
* Fix pillow backwards compatibility, add mozjpeg-lossless-optimization to setup.py by @corylk in #461
|
||||
* fix in fedora: 7z doesn't support rar archives, use unrar by @AlicesReflexion in #370
|
||||
* Using communicate instead of terminate by @catsout in #459
|
||||
* use copyfile and delete instead of shutil.move fix #386 by @StudioEtrange in #387
|
||||
|
||||
|
||||
#### 5.6.0:
|
||||
* Fix Docker 7z missing [darodi/kcc#31](https://github.com/darodi/kcc/issues/31), thanks [@darodi](https://github.com/darodi)
|
||||
* update to python 3.11, thanks [@darodi](https://github.com/darodi)
|
||||
|
||||
235
README.md
235
README.md
@@ -1,16 +1,10 @@
|
||||
# KCC
|
||||
|
||||
[](https://github.com/ciromattia/kcc/releases)
|
||||
[](https://test.pypi.org/project/KindleComicConverterDarodi/)
|
||||
|
||||
[](https://github.com/darodi/kcc/pkgs/container/kcc)
|
||||
|
||||
[//]: # ([](https://aur.archlinux.org/packages/kcc-beta))
|
||||
|
||||
|
||||
[](https://github.com/ciromattia/kcc/releases)
|
||||
[](https://pypi.python.org/pypi/KindleComicConverter)
|
||||
[](https://aur.archlinux.org/packages/kcc/)
|
||||
[](https://github.com/ciromattia/kcc/pkgs/container/kcc)
|
||||
|
||||
|
||||
**Kindle Comic Converter** is a Python app to convert comic/manga files or folders to EPUB, Panel View MOBI or E-Ink optimized CBZ.
|
||||
It was initially developed for Kindle but since version 4.6 it outputs valid EPUB 3.0 so _**despite its name, KCC is
|
||||
@@ -38,138 +32,18 @@ If you find **KCC** valuable you can consider donating to the authors:
|
||||
|
||||
## INSTALLATION
|
||||
|
||||
|
||||
|
||||
### BINARY RELEASES
|
||||
You can find the latest binary at the following link:
|
||||
|
||||
- **https://github.com/ciromattia/kcc/releases**
|
||||
|
||||
- flatpak : https://flathub.org/apps/details/io.github.ciromattia.kcc
|
||||
- Docker: https://github.com/ciromattia/kcc/pkgs/container/kcc
|
||||
|
||||
~~- **[Windows](http://kcc.iosphe.re/Windows/) (64-bit only)**~~
|
||||
~~- **[macOS](http://kcc.iosphe.re/OSX/) (10.14+)**~~
|
||||
~~- **Linux:** Currently unavailable.~~
|
||||
|
||||
|
||||
|
||||
#### MacOS installation
|
||||
##### x86_64 version
|
||||
see: KindleComicConverter_osx_*.dmg in **https://github.com/ciromattia/kcc/releases**
|
||||
If you can't open the last beta and the OS says it's damaged, fix it with:
|
||||
```
|
||||
xattr -d com.apple.quarantine /Applications/Kindle\ Comic\ Converter.app
|
||||
```
|
||||
|
||||
##### M1/M2 arm64 version
|
||||
|
||||
Building is not available in github on M1 arch.
|
||||
See this building method, to build it locally:
|
||||
_Originally posted by @celogeek in https://github.com/darodi/kcc/issues/4#issuecomment-1364553511_
|
||||
|
||||
|
||||
If you can't open the last beta and the OS says it's damaged, fix it with:
|
||||
```
|
||||
xattr -d com.apple.quarantine /Applications/Kindle\ Comic\ Converter.app
|
||||
```
|
||||
|
||||
Or you could also have a look at this other project:
|
||||
https://github.com/celogeek/go-comic-converter
|
||||
|
||||
#### Linux installation
|
||||
- make binary executable
|
||||
```bash
|
||||
$ chmod a+x kcc_linux
|
||||
```
|
||||
- install 7zip
|
||||
```bash
|
||||
$ sudo apt-get install -y p7zip-full
|
||||
```
|
||||
- Download kindlegen
|
||||
```bash
|
||||
$ wget -qO- https://archive.org/download/kindlegen_linux_2_6_i386_v2_9/kindlegen_linux_2.6_i386_v2_9.tar.gz | tar xvz kindlegen
|
||||
```
|
||||
- copy kindlegen into '/usr/local/bin' and grant execute permissions for MOBI conversion.
|
||||
```bash
|
||||
$ sudo cp -R kindlegen /usr/local/bin && sudo chmod a+x /usr/local/bin/kindlegen
|
||||
```
|
||||
- run with backend x11 or it might not work with fedora
|
||||
```bash
|
||||
$ GDK_BACKEND=x11 ./kcc_linux
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### PYPI
|
||||
**KCC** is also available on PyPI.
|
||||
On Debian based distributions these two commands should install all needed dependencies:
|
||||
```bash
|
||||
$ sudo apt-get install python3 python3-dev python3-pip libpng-dev libjpeg-dev p7zip-full python3-pyqt5
|
||||
$ pip3 install --user --upgrade pillow python-slugify psutil pyqt5 raven
|
||||
```
|
||||
beta version
|
||||
```bash
|
||||
$ pip install --index-url https://test.pypi.org/simple/ KindleComicConverterDarodi
|
||||
```
|
||||
|
||||
stable version
|
||||
```bash
|
||||
$ pip install --user KindleComicConverter
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### APPIMAGE
|
||||
- install 7zip
|
||||
```bash
|
||||
$ sudo apt-get install -y p7zip-full
|
||||
```
|
||||
- Download kindlegen
|
||||
```bash
|
||||
$ wget -qO- https://archive.org/download/kindlegen_linux_2_6_i386_v2_9/kindlegen_linux_2.6_i386_v2_9.tar.gz | tar xvz kindlegen
|
||||
```
|
||||
- copy kindlegen into '/usr/local/bin' and grant execute permissions for MOBI conversion.
|
||||
```bash
|
||||
$ sudo cp -R kindlegen /usr/local/bin && sudo chmod a+x /usr/local/bin/kindlegen
|
||||
```
|
||||
- make appImage executable
|
||||
```bash
|
||||
$ chmod a+x kindleComicConverter-latest-x86_64.AppImage
|
||||
```
|
||||
- run with backend x11 or it might not work with fedora
|
||||
```bash
|
||||
$ GDK_BACKEND=x11 ./kindleComicConverter-latest-x86_64.AppImage
|
||||
```
|
||||
|
||||
|
||||
### DOCKER
|
||||
|
||||
install kindlegen in your working directory and get last docker image
|
||||
```bash
|
||||
$ wget -qO- https://archive.org/download/kindlegen_linux_2_6_i386_v2_9/kindlegen_linux_2.6_i386_v2_9.tar.gz | tar xvz kindlegen
|
||||
```
|
||||
```bash
|
||||
$ docker pull ghcr.io/ciromattia/kcc:latest
|
||||
```
|
||||
|
||||
execute kcc-c2e
|
||||
```bash
|
||||
$ docker run --rm -v "$(pwd):/app" ghcr.io/ciromattia/kcc:latest
|
||||
```
|
||||
|
||||
example
|
||||
```bash
|
||||
$ docker run --rm -v "$(pwd):/app" ghcr.io/ciromattia/kcc:latest -p KPW5 ./1.cbz
|
||||
```
|
||||
|
||||
execute kcc-c2p
|
||||
```bash
|
||||
$ docker run --entrypoint /opt/kcc/kcc-c2p.py --rm -v "$(pwd):/app" ghcr.io/ciromattia/kcc:latest
|
||||
```
|
||||
~~- **Linux:** Currently unavailable.~~
|
||||
|
||||
more information on [installation](https://github.com/ciromattia/kcc/wiki/Installation)
|
||||
|
||||
### DEPENDENCIES
|
||||
Following software is required to run Linux version of **KCC** and/or bare sources:
|
||||
@@ -181,92 +55,27 @@ Following software is required to run Linux version of **KCC** and/or bare sourc
|
||||
- [raven](https://pypi.python.org/pypi/raven) 6.0.0+ (only needed for GUI)
|
||||
|
||||
On Debian based distributions these two commands should install all needed dependencies:
|
||||
```bash
|
||||
$ sudo apt-get install python3 python3-dev python3-pip libpng-dev libjpeg-dev p7zip-full python3-pyqt5
|
||||
|
||||
$ pip3 install --user --upgrade pillow python-slugify psutil pyqt5 raven
|
||||
|
||||
|
||||
```bash
|
||||
$ sudo apt-get install -y python3 python3-dev libpng-dev libjpeg-dev p7zip-full p7zip-rar unrar-free libgl1 python3-pyqt5 && \
|
||||
python -m pip install --upgrade pip && \
|
||||
python -m pip install --upgrade -r requirements.txt
|
||||
```
|
||||
|
||||
|
||||
#### Optional dependencies
|
||||
- Qt platform integration plugin for Deepin Desktop Environment
|
||||
```bash
|
||||
$ sudo apt-get install qt5dxcb-plugin
|
||||
```
|
||||
|
||||
- KindleGen ~~[deprecated link](http://www.amazon.com/gp/feature.html?ie=UTF8&docId=1000765211)~~ v2.9+ in a directory reachable by your _PATH_ or in _KCC_ directory *(For MOBI generation)
|
||||
– which offers a command line interface and supports [Linux](https://archive.org/details/kindlegen2.9) [(mirror1)](https://archive.org/download/kindlegen_linux_2_6_i386_v2_9/kindlegen_linux_2.6_i386_v2_9.tar.gz), [Mac OSX](https://web.archive.org/web/20190905040839/https://www.amazon.com/gp/feature.html?ie=UTF8&docId=1000765211) and [Windows](https://archive.org/details/kindlegen_win32_v2_9) – has been deprecated, but binaries can still be found on the internet.
|
||||
- KindleGen ~~[deprecated link](http://www.amazon.com/gp/feature.html?ie=UTF8&docId=1000765211)~~ v2.9+ in a directory reachable by your _PATH_ or in _KCC_ directory *(For MOBI generation)
|
||||
- It can be found in [Kindle Previewer](https://www.amazon.com/Kindle-Previewer/b?ie=UTF8&node=21381691011)
|
||||
`Amazon Kindle Previewer 3 Folder\lib\fc\bin`, the usual location in windows is in windows is `C:\Users\user\AppData\Local\Amazon\Kindle Previewer 3\lib\fc\bin\`
|
||||
- [7z](http://www.7-zip.org/download.html) *(For CBZ/ZIP, CBR/RAR, 7z/CB7 support)*
|
||||
|
||||
### INSTALL FROM SOURCES
|
||||
|
||||
_Originally posted by @hhtien1408 in https://github.com/ciromattia/kcc/issues/438#issuecomment-1281159452_
|
||||
|
||||
```bash
|
||||
$ git clone https://github.com/ciromattia/kcc.git
|
||||
```
|
||||
On Debian based distributions these two commands should install all needed dependencies:
|
||||
```bash
|
||||
$ sudo apt-get install python3 python3-dev python3-pip libpng-dev libjpeg-dev p7zip-full python3-pyqt5
|
||||
```
|
||||
Then install the necessary packages. You can do it by running the following command. The requirements.txt file is inside this repository, you will see it when you clone the repo.
|
||||
|
||||
```bash
|
||||
$ pip3 install -r 'requirements.txt'
|
||||
```
|
||||
|
||||
This should install the required packages. You can check the version by running
|
||||
|
||||
```bash
|
||||
$ pip3 freeze
|
||||
```
|
||||
|
||||
If the packages are in the wrong version, you can try to upgrade them by running
|
||||
|
||||
```bash
|
||||
$ pip3 install --upgrade name_of_the_package
|
||||
```
|
||||
|
||||
Download kindlegen.
|
||||
|
||||
```bash
|
||||
$ wget https://archive.org/download/kindlegen_linux_2_6_i386_v2_9/kindlegen_linux_2.6_i386_v2_9.tar.gz | tar xvzf kindlegen
|
||||
```
|
||||
Copy kindlegen into '/usr/local/bin' and grant execute permissions for MOBI conversion.
|
||||
|
||||
```bash
|
||||
$ sudo cp -R '/home/user/Desktop/kindlegen' '/usr/local/bin'
|
||||
|
||||
$ sudo chmod +rwx '/usr/local/bin/kindlegen'
|
||||
```
|
||||
|
||||
|
||||
Run python file for KCC GUI
|
||||
```bash
|
||||
$ python3 kcc.py
|
||||
```
|
||||
|
||||
If everything goes well, you now should be able to use it.
|
||||
|
||||
Create destop file in '~/.local/share/applications' with codes:
|
||||
|
||||
```
|
||||
#!/usr/bin/env xdg-open
|
||||
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
Name=Kindle Comic Converter
|
||||
Icon=kcc
|
||||
Exec=python3 '/home/user/kcc/kcc.py'
|
||||
Terminal=false
|
||||
StartupWMClass=kcc
|
||||
Name[en_US]=Kindle Comic Converter
|
||||
```
|
||||
|
||||
Copy icon file into '/home/user/.local/share/icons'
|
||||
|
||||
```bash
|
||||
$ sudo cp -R 'icons/comic2ebook.png' '/home/user/.local/share/icons'
|
||||
```
|
||||
- Unrar (no rar in 7z on Fedora)
|
||||
|
||||
|
||||
|
||||
@@ -278,6 +87,8 @@ $ sudo cp -R 'icons/comic2ebook.png' '/home/user/.local/share/icons'
|
||||
- CB7, 7Z *(With `7z` executable)*
|
||||
- PDF *(Only extracting JPG images)*
|
||||
|
||||
Add 7z to PATH via `setx path "%path%;C:\Program Files\7-Zip"`
|
||||
|
||||
## USAGE
|
||||
|
||||
Should be pretty self-explanatory. All options have detailed information in tooltips.
|
||||
@@ -286,6 +97,10 @@ After completed conversion, you should find ready file alongside the original in
|
||||
Please check [our wiki](https://github.com/ciromattia/kcc/wiki/) for more details.
|
||||
|
||||
CLI version of **KCC** is intended for power users. It allows using options that might not be compatible and decrease the quality of output.
|
||||
CLI version has reduced dependencies, on Debian based distributions this commands should install all needed dependencies:
|
||||
```
|
||||
sudo apt-get install python3 p7zip-full python3-pil python3-psutil python3-slugify
|
||||
```
|
||||
|
||||
### Profiles:
|
||||
|
||||
@@ -367,12 +182,16 @@ Options:
|
||||
page numbers [Default=2]
|
||||
--cp=CROPPINGP, --croppingpower=CROPPINGP
|
||||
Set cropping power [Default=1.0]
|
||||
--cm=CROPPINGM, --croppingminimum=CROPPINGM
|
||||
Set cropping minimum area ratio [Default=0.0]
|
||||
--blackborders Disable autodetection and force black borders
|
||||
--whiteborders Disable autodetection and force white borders
|
||||
--forcecolor Don't convert images to grayscale
|
||||
--forcepng Create PNG files instead JPEG
|
||||
--mozjpeg Create JPEG files using mozJpeg
|
||||
--maximizestrips Turn 1x4 strips to 2x2 strips
|
||||
-d, --delete Delete source file(s) or a directory. It's not
|
||||
recoverable.
|
||||
|
||||
CUSTOM PROFILE:
|
||||
--customwidth=CUSTOMWIDTH
|
||||
|
||||
15
gui/KCC.ui
15
gui/KCC.ui
@@ -175,10 +175,20 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QCheckBox" name="deleteBox">
|
||||
<property name="toolTip">
|
||||
<string>Delete input file(s) or directory. It's not recoverable!</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Delete input</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="2">
|
||||
<widget class="QCheckBox" name="disableProcessingBox">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p style='white-space:pre'>Do not process any image, ignore profil and processing options</p></body></html></string>
|
||||
<string><html><head/><body><pre style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Do not process any image, ignore profile and processing options</pre></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Disable processing</string>
|
||||
@@ -257,7 +267,7 @@
|
||||
<item>
|
||||
<widget class="QSlider" name="croppingPowerSlider">
|
||||
<property name="maximum">
|
||||
<number>10</number>
|
||||
<number>200</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>1</number>
|
||||
@@ -600,6 +610,7 @@
|
||||
<tabstop>croppingBox</tabstop>
|
||||
<tabstop>mozJpegBox</tabstop>
|
||||
<tabstop>maximizeStrips</tabstop>
|
||||
<tabstop>deleteBox</tabstop>
|
||||
<tabstop>disableProcessingBox</tabstop>
|
||||
<tabstop>editorButton</tabstop>
|
||||
<tabstop>wikiButton</tabstop>
|
||||
|
||||
39
kcc-c2e.spec
Normal file
39
kcc-c2e.spec
Normal file
@@ -0,0 +1,39 @@
|
||||
# -*- mode: python ; coding: utf-8 -*-
|
||||
|
||||
|
||||
block_cipher = None
|
||||
|
||||
|
||||
a = Analysis(['kcc-c2e.py'],
|
||||
pathex=['.'],
|
||||
binaries=[],
|
||||
datas=[],
|
||||
hiddenimports=[],
|
||||
hookspath=[],
|
||||
runtime_hooks=[],
|
||||
excludes=[],
|
||||
win_no_prefer_redirects=False,
|
||||
win_private_assemblies=False,
|
||||
cipher=block_cipher,
|
||||
noarchive=False)
|
||||
pyz = PYZ(a.pure, a.zipped_data,
|
||||
cipher=block_cipher)
|
||||
|
||||
exe = EXE(pyz,
|
||||
a.scripts,
|
||||
a.binaries,
|
||||
a.zipfiles,
|
||||
a.datas,
|
||||
[],
|
||||
name='kcc-c2e',
|
||||
debug=False,
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
upx=False,
|
||||
upx_exclude=[],
|
||||
runtime_tmpdir=None,
|
||||
console=True,
|
||||
disable_windowed_traceback=False,
|
||||
target_arch=None,
|
||||
codesign_identity=None,
|
||||
entitlements_file=None , icon='icons\\comic2ebook.ico')
|
||||
39
kcc-c2p.spec
Normal file
39
kcc-c2p.spec
Normal file
@@ -0,0 +1,39 @@
|
||||
# -*- mode: python ; coding: utf-8 -*-
|
||||
|
||||
|
||||
block_cipher = None
|
||||
|
||||
|
||||
a = Analysis(['kcc-c2p.py'],
|
||||
pathex=['.'],
|
||||
binaries=[],
|
||||
datas=[],
|
||||
hiddenimports=[],
|
||||
hookspath=[],
|
||||
runtime_hooks=[],
|
||||
excludes=[],
|
||||
win_no_prefer_redirects=False,
|
||||
win_private_assemblies=False,
|
||||
cipher=block_cipher,
|
||||
noarchive=False)
|
||||
pyz = PYZ(a.pure, a.zipped_data,
|
||||
cipher=block_cipher)
|
||||
|
||||
exe = EXE(pyz,
|
||||
a.scripts,
|
||||
a.binaries,
|
||||
a.zipfiles,
|
||||
a.datas,
|
||||
[],
|
||||
name='kcc-c2p',
|
||||
debug=False,
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
upx=False,
|
||||
upx_exclude=[],
|
||||
runtime_tmpdir=None,
|
||||
console=True,
|
||||
disable_windowed_traceback=False,
|
||||
target_arch=None,
|
||||
codesign_identity=None,
|
||||
entitlements_file=None , icon='icons\\comic2ebook.ico')
|
||||
10
kcc.py
10
kcc.py
@@ -28,16 +28,20 @@ import os
|
||||
if sys.platform.startswith('darwin'):
|
||||
if getattr(sys, 'frozen', False):
|
||||
os.environ['PATH'] = os.path.dirname(os.path.abspath(sys.executable)) + \
|
||||
'/../Resources:/Applications/Kindle Comic Creator/Kindle Comic Creator.app/Contents/' \
|
||||
'MacOS:/usr/local/bin:/usr/bin:/bin'
|
||||
'/../Resources:/Applications/Kindle Comic Creator/Kindle Comic Creator.app/Contents/MacOS:' \
|
||||
'/Applications/Kindle Previewer 3.app/Contents/lib/fc/bin/:/usr/local/bin:/usr/bin:/bin'
|
||||
os.chdir(os.path.dirname(os.path.abspath(sys.executable)) + '/../Resources')
|
||||
else:
|
||||
os.chdir(os.path.dirname(os.path.abspath(__file__)))
|
||||
elif sys.platform.startswith('win'):
|
||||
if getattr(sys, 'frozen', False):
|
||||
os.environ['PATH'] = '%LOCALAPPDATA%\\Amazon\\Kindle Previewer 3\\lib\\fc\\bin\\;' + \
|
||||
os.environ['PATH']
|
||||
os.chdir(os.path.dirname(os.path.abspath(sys.executable)))
|
||||
else:
|
||||
os.environ['PATH'] = os.path.dirname(os.path.abspath(__file__)) + '/other/windows/;' + os.environ['PATH']
|
||||
os.environ['PATH'] = os.path.dirname(os.path.abspath(__file__)) + '/other/windows/;' \
|
||||
'%LOCALAPPDATA%\\Amazon\\Kindle Previewer 3\\lib\\fc\\bin\\;' + \
|
||||
os.environ['PATH']
|
||||
os.chdir(os.path.dirname(os.path.abspath(__file__)))
|
||||
# Load additional Sentry configuration
|
||||
# if getattr(sys, 'frozen', False):
|
||||
|
||||
39
kcc.spec
Normal file
39
kcc.spec
Normal file
@@ -0,0 +1,39 @@
|
||||
# -*- mode: python ; coding: utf-8 -*-
|
||||
|
||||
|
||||
block_cipher = None
|
||||
|
||||
|
||||
a = Analysis(['kcc.py'],
|
||||
pathex=['.'],
|
||||
binaries=[],
|
||||
datas=[],
|
||||
hiddenimports=[],
|
||||
hookspath=[],
|
||||
runtime_hooks=[],
|
||||
excludes=[],
|
||||
win_no_prefer_redirects=False,
|
||||
win_private_assemblies=False,
|
||||
cipher=block_cipher,
|
||||
noarchive=False)
|
||||
pyz = PYZ(a.pure, a.zipped_data,
|
||||
cipher=block_cipher)
|
||||
|
||||
exe = EXE(pyz,
|
||||
a.scripts,
|
||||
a.binaries,
|
||||
a.zipfiles,
|
||||
a.datas,
|
||||
[],
|
||||
name='kcc',
|
||||
debug=False,
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
upx=False,
|
||||
upx_exclude=[],
|
||||
runtime_tmpdir=None,
|
||||
console=False,
|
||||
disable_windowed_traceback=False,
|
||||
target_arch=None,
|
||||
codesign_identity=None,
|
||||
entitlements_file=None , icon='icons\\comic2ebook.ico')
|
||||
@@ -294,6 +294,8 @@ class WorkerThread(QtCore.QThread):
|
||||
options.maximizestrips = True
|
||||
if GUI.disableProcessingBox.isChecked():
|
||||
options.noprocessing = True
|
||||
if GUI.deleteBox.isChecked():
|
||||
options.delete = True
|
||||
if GUI.mozJpegBox.checkState() == 1:
|
||||
options.forcepng = True
|
||||
elif GUI.mozJpegBox.checkState() == 2:
|
||||
@@ -786,7 +788,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
||||
if sys.platform.startswith('win'):
|
||||
self.addMessage('Download it and place EXE in KCC directory.', 'error')
|
||||
elif sys.platform.startswith('darwin'):
|
||||
self.addMessage('Install it using <a href="http://brew.sh/">Brew</a>.', 'error')
|
||||
self.addMessage('Install it using <a href="http://brew.sh/">Homebrew</a>.', 'error')
|
||||
else:
|
||||
self.addMessage('Download it and place executable in /usr/local/bin directory.', 'error')
|
||||
self.needClean = True
|
||||
@@ -823,6 +825,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
||||
'mozJpegBox': GUI.mozJpegBox.checkState(),
|
||||
'widthBox': GUI.widthBox.value(),
|
||||
'heightBox': GUI.heightBox.value(),
|
||||
'deleteBox': GUI.deleteBox.checkState(),
|
||||
'maximizeStrips': GUI.maximizeStrips.checkState(),
|
||||
'gammaSlider': float(self.gammaValue) * 100})
|
||||
self.settings.sync()
|
||||
@@ -896,8 +899,9 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
||||
if sys.platform.startswith('win'):
|
||||
self.addMessage('Download it and place EXE in KCC directory.', 'error')
|
||||
elif sys.platform.startswith('darwin'):
|
||||
self.addMessage('Install it using <a href="http://brew.sh/">Brew</a>: <i>brew cask install kindle-c'
|
||||
'omic-creator</i>', 'error')
|
||||
self.addMessage('Install it using <a href="http://brew.sh/">Homebrew</a>: '
|
||||
'<i>brew install --cask kindle-comic-creator</i> or '
|
||||
'<i>brew install --cask kindle-previewer</i>', 'error')
|
||||
else:
|
||||
self.addMessage('Download it and place executable in /usr/local/bin directory.', 'error')
|
||||
|
||||
@@ -1071,7 +1075,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
||||
self.sevenzip = True
|
||||
else:
|
||||
self.sevenzip = False
|
||||
self.addMessage('Cannot find <a href="http://www.7-zip.org/download.html">7z</a>!'
|
||||
self.addMessage('Add <a href="http://www.7-zip.org/download.html">7z</a> to PATH!'
|
||||
' Processing of archives will be disabled.', 'warning')
|
||||
self.detectKindleGen(True)
|
||||
|
||||
@@ -1149,7 +1153,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
||||
self.versionCheck.start()
|
||||
self.tray.show()
|
||||
|
||||
# Cleanup unfisnished conversion
|
||||
# Cleanup unfinished conversion
|
||||
for root, dirs, _ in walkLevel(gettempdir(), 0):
|
||||
for tempdir in dirs:
|
||||
if tempdir.startswith('KCC-'):
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
# Form implementation generated from reading ui file 'gui/KCC.ui'
|
||||
#
|
||||
# Created by: PyQt5 UI code generator 5.15.6
|
||||
# Created by: PyQt5 UI code generator 5.15.7
|
||||
#
|
||||
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
|
||||
# run again. Do not edit this file unless you know what you are doing.
|
||||
@@ -70,6 +70,9 @@ class Ui_mainWindow(object):
|
||||
self.croppingBox.setTristate(True)
|
||||
self.croppingBox.setObjectName("croppingBox")
|
||||
self.gridLayout_2.addWidget(self.croppingBox, 3, 2, 1, 1)
|
||||
self.deleteBox = QtWidgets.QCheckBox(self.optionWidget)
|
||||
self.deleteBox.setObjectName("deleteBox")
|
||||
self.gridLayout_2.addWidget(self.deleteBox, 4, 1, 1, 1)
|
||||
self.disableProcessingBox = QtWidgets.QCheckBox(self.optionWidget)
|
||||
self.disableProcessingBox.setObjectName("disableProcessingBox")
|
||||
self.gridLayout_2.addWidget(self.disableProcessingBox, 4, 2, 1, 1)
|
||||
@@ -254,7 +257,8 @@ class Ui_mainWindow(object):
|
||||
mainWindow.setTabOrder(self.colorBox, self.croppingBox)
|
||||
mainWindow.setTabOrder(self.croppingBox, self.mozJpegBox)
|
||||
mainWindow.setTabOrder(self.mozJpegBox, self.maximizeStrips)
|
||||
mainWindow.setTabOrder(self.maximizeStrips, self.disableProcessingBox)
|
||||
mainWindow.setTabOrder(self.maximizeStrips, self.deleteBox)
|
||||
mainWindow.setTabOrder(self.deleteBox, self.disableProcessingBox)
|
||||
mainWindow.setTabOrder(self.disableProcessingBox, self.editorButton)
|
||||
mainWindow.setTabOrder(self.editorButton, self.wikiButton)
|
||||
mainWindow.setTabOrder(self.wikiButton, self.jobList)
|
||||
@@ -290,7 +294,9 @@ class Ui_mainWindow(object):
|
||||
self.maximizeStrips.setText(_translate("mainWindow", "1x4 to 2x2 strips"))
|
||||
self.croppingBox.setToolTip(_translate("mainWindow", "<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Disabled</span></p><p>Disabled</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - Margins<br/></span>Margins</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Margins + page numbers<br/></span>Margins +page numbers</p></body></html>"))
|
||||
self.croppingBox.setText(_translate("mainWindow", "Cropping mode"))
|
||||
self.disableProcessingBox.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Do not process any image, ignore profil and processing options</p></body></html>"))
|
||||
self.deleteBox.setToolTip(_translate("mainWindow", "Delete input file(s) or directory. It\'s not recoverable!"))
|
||||
self.deleteBox.setText(_translate("mainWindow", "Delete input"))
|
||||
self.disableProcessingBox.setToolTip(_translate("mainWindow", "<html><head/><body><pre style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">Do not process any image, ignore profile and processing options</pre></body></html>"))
|
||||
self.disableProcessingBox.setText(_translate("mainWindow", "Disable processing"))
|
||||
self.gammaLabel.setText(_translate("mainWindow", "Gamma: Auto"))
|
||||
self.croppingPowerLabel.setText(_translate("mainWindow", "Cropping power:"))
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
__version__ = '5.6.0'
|
||||
__version__ = '5.6.2'
|
||||
__license__ = 'ISC'
|
||||
__copyright__ = '2012-2022, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>, darodi'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
@@ -27,7 +27,7 @@ from re import sub
|
||||
from stat import S_IWRITE, S_IREAD, S_IEXEC
|
||||
from zipfile import ZipFile, ZIP_STORED, ZIP_DEFLATED
|
||||
from tempfile import mkdtemp, gettempdir, TemporaryFile
|
||||
from shutil import move, copytree, rmtree
|
||||
from shutil import move, copytree, rmtree, copyfile
|
||||
from optparse import OptionParser, OptionGroup
|
||||
from multiprocessing import Pool
|
||||
from uuid import uuid4
|
||||
@@ -302,6 +302,11 @@ def buildOPF(dstdir, title, filelist, cover=None):
|
||||
else:
|
||||
f.writelines(["<meta name=\"orientation-lock\" content=\"portrait\"/>\n",
|
||||
"<meta name=\"region-mag\" content=\"true\"/>\n"])
|
||||
elif options.supportSyntheticSpread:
|
||||
f.writelines([
|
||||
"<meta property=\"rendition:spread\">landscape</meta>\n",
|
||||
"<meta property=\"rendition:layout\">pre-paginated</meta>\n"
|
||||
])
|
||||
else:
|
||||
f.writelines(["<meta property=\"rendition:orientation\">portrait</meta>\n",
|
||||
"<meta property=\"rendition:spread\">portrait</meta>\n",
|
||||
@@ -334,38 +339,64 @@ def buildOPF(dstdir, title, filelist, cover=None):
|
||||
f.write("<item id=\"img_" + str(uniqueid) + "\" href=\"" + folder + "/" + path[1] + "\" media-type=\"" +
|
||||
mt + "\"/>\n")
|
||||
f.write("<item id=\"css\" href=\"Text/style.css\" media-type=\"text/css\"/>\n")
|
||||
|
||||
|
||||
def pageSpreadProperty(pageside):
|
||||
if options.iskindle:
|
||||
return "linear=\"yes\" properties=\"page-spread-%s\"" % pageside
|
||||
elif options.isKobo:
|
||||
return "properties=\"rendition:page-spread-%s\"" % pageside
|
||||
else:
|
||||
return ""
|
||||
|
||||
if options.righttoleft:
|
||||
f.write("</manifest>\n<spine page-progression-direction=\"rtl\" toc=\"ncx\">\n")
|
||||
pageside = "right"
|
||||
else:
|
||||
f.write("</manifest>\n<spine page-progression-direction=\"ltr\" toc=\"ncx\">\n")
|
||||
pageside = "left"
|
||||
if options.iskindle:
|
||||
if options.iskindle or options.supportSyntheticSpread:
|
||||
for entry in reflist:
|
||||
if options.righttoleft:
|
||||
if entry.endswith("-b"):
|
||||
f.write("<itemref idref=\"page_" + entry + "\" linear=\"yes\" properties=\"page-spread-right\"/>\n")
|
||||
f.write(
|
||||
"<itemref idref=\"page_%s\" %s/>\n" % (entry,
|
||||
pageSpreadProperty("right"))
|
||||
)
|
||||
pageside = "right"
|
||||
elif entry.endswith("-c"):
|
||||
f.write("<itemref idref=\"page_" + entry + "\" linear=\"yes\" properties=\"page-spread-left\"/>\n")
|
||||
f.write(
|
||||
"<itemref idref=\"page_%s\" %s/>\n" % (entry,
|
||||
pageSpreadProperty("left"))
|
||||
)
|
||||
pageside = "right"
|
||||
else:
|
||||
f.write("<itemref idref=\"page_" + entry + "\" linear=\"yes\" properties=\"page-spread-" +
|
||||
pageside + "\"/>\n")
|
||||
f.write(
|
||||
"<itemref idref=\"page_%s\" %s/>\n" % (entry,
|
||||
pageSpreadProperty(pageside))
|
||||
)
|
||||
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")
|
||||
f.write(
|
||||
"<itemref idref=\"page_%s\" %s/>\n" % (entry,
|
||||
pageSpreadProperty("left"))
|
||||
)
|
||||
pageside = "left"
|
||||
elif entry.endswith("-c"):
|
||||
f.write("<itemref idref=\"page_" + entry + "\" linear=\"yes\" properties=\"page-spread-right\"/>\n")
|
||||
f.write(
|
||||
"<itemref idref=\"page_%s\" %s/>\n" % (entry,
|
||||
pageSpreadProperty("right"))
|
||||
)
|
||||
pageside = "left"
|
||||
else:
|
||||
f.write("<itemref idref=\"page_" + entry + "\" linear=\"yes\" properties=\"page-spread-" +
|
||||
pageside + "\"/>\n")
|
||||
f.write(
|
||||
"<itemref idref=\"page_%s\" %s/>\n" % (entry,
|
||||
pageSpreadProperty(pageside))
|
||||
)
|
||||
if pageside == "right":
|
||||
pageside = "left"
|
||||
else:
|
||||
@@ -557,9 +588,9 @@ def imgFileProcessing(work):
|
||||
for i in workImg.payload:
|
||||
img = image.ComicPage(opt, *i)
|
||||
if opt.cropping == 2 and not opt.webtoon:
|
||||
img.cropPageNumber(opt.croppingp)
|
||||
img.cropPageNumber(opt.croppingp, opt.croppingm)
|
||||
if opt.cropping > 0 and not opt.webtoon:
|
||||
img.cropMargin(opt.croppingp)
|
||||
img.cropMargin(opt.croppingp, opt.croppingm)
|
||||
img.autocontrastImage()
|
||||
img.resizeImage()
|
||||
if opt.forcepng and not opt.forcecolor:
|
||||
@@ -951,6 +982,8 @@ def makeParser():
|
||||
help="Set cropping mode. 0: Disabled 1: Margins 2: Margins + page numbers [Default=2]")
|
||||
processingOptions.add_option("--cp", "--croppingpower", type="float", dest="croppingp", default="1.0",
|
||||
help="Set cropping power [Default=1.0]")
|
||||
processingOptions.add_option("--cm", "--croppingminimum", type="float", dest="croppingm", default="0.0",
|
||||
help="Set cropping minimum area ratio [Default=0.0]")
|
||||
processingOptions.add_option("--blackborders", action="store_true", dest="black_borders", default=False,
|
||||
help="Disable autodetection and force black borders")
|
||||
processingOptions.add_option("--whiteborders", action="store_true", dest="white_borders", default=False,
|
||||
@@ -963,6 +996,9 @@ def makeParser():
|
||||
help="Create JPEG files using mozJpeg")
|
||||
processingOptions.add_option("--maximizestrips", action="store_true", dest="maximizestrips", default=False,
|
||||
help="Turn 1x4 strips to 2x2 strips")
|
||||
processingOptions.add_option("-d", "--delete", action="store_true", dest="delete", default=False,
|
||||
help="Delete source file(s) or a directory. It's not recoverable.")
|
||||
|
||||
customProfileOptions.add_option("--customwidth", type="int", dest="customwidth", default=0,
|
||||
help="Replace screen width provided by device profile")
|
||||
customProfileOptions.add_option("--customheight", type="int", dest="customheight", default=0,
|
||||
@@ -982,10 +1018,11 @@ def makeParser():
|
||||
def checkOptions(options):
|
||||
options.panelview = True
|
||||
options.iskindle = False
|
||||
options.isKobo = False
|
||||
options.bordersColor = None
|
||||
options.keep_epub = False
|
||||
if options.format == 'EPUB-200MB':
|
||||
options.targetsize = 200
|
||||
options.targetsize = 195
|
||||
options.format = 'EPUB'
|
||||
if options.batchsplit != 2:
|
||||
options.batchsplit = 1
|
||||
@@ -993,6 +1030,7 @@ def checkOptions(options):
|
||||
options.keep_epub = True
|
||||
options.format = 'MOBI'
|
||||
options.kfx = False
|
||||
options.supportSyntheticSpread = False
|
||||
if options.format == 'Auto':
|
||||
if options.profile in ['K1', 'K2', 'K34', 'K578', 'KPW', 'KPW5', 'KV', 'KO', 'K11', 'KS']:
|
||||
options.format = 'MOBI'
|
||||
@@ -1003,6 +1041,12 @@ def checkOptions(options):
|
||||
options.format = 'CBZ'
|
||||
if options.profile in ['K1', 'K2', 'K34', 'K578', 'KPW', 'KPW5', 'KV', 'KO', 'K11', 'KS']:
|
||||
options.iskindle = True
|
||||
elif options.profile in ['OTHER', 'KoMT', 'KoG', 'KoGHD', 'KoA', 'KoAHD', 'KoAH2O', 'KoAO', 'KoN', 'KoC', 'KoL', 'KoF', 'KoS', 'KoE']:
|
||||
options.isKobo = True
|
||||
# Other Kobo devices probably support synthetic spreads as well, but
|
||||
# they haven't been tested.
|
||||
if options.profile in ['KoF']:
|
||||
options.supportSyntheticSpread = True
|
||||
if options.white_borders:
|
||||
options.bordersColor = 'white'
|
||||
if options.black_borders:
|
||||
@@ -1048,6 +1092,10 @@ def checkOptions(options):
|
||||
image.ProfileData.Profiles["Custom"] = newProfile
|
||||
options.profile = "Custom"
|
||||
options.profileData = image.ProfileData.Profiles[options.profile]
|
||||
# kindle scribe conversion to mobi is limited in resolution by kindlegen, same with send to kindle and epub
|
||||
if options.profile == 'KS' and (options.format == 'MOBI' or options.format == 'EPUB'):
|
||||
options.profileData = list(options.profileData)
|
||||
options.profileData[1] = (1440, 1920)
|
||||
return options
|
||||
|
||||
|
||||
@@ -1103,7 +1151,7 @@ def makeBook(source, qtgui=None):
|
||||
y = image.ProfileData.Profiles[options.profile][1][1]
|
||||
comic2panel.main(['-y ' + str(y), '-i', '-m', path], qtgui)
|
||||
if options.noprocessing:
|
||||
print("Do not process image, ignore any profil or processing option")
|
||||
print("Do not process image, ignore any profile or processing option")
|
||||
else:
|
||||
print("Processing images...")
|
||||
if GUI:
|
||||
@@ -1152,7 +1200,12 @@ def makeBook(source, qtgui=None):
|
||||
else:
|
||||
filepath.append(getOutputFilename(source, options.output, '.epub', ''))
|
||||
makeZIP(tome + '_comic', tome, True)
|
||||
move(tome + '_comic.zip', filepath[-1])
|
||||
copyfile(tome + '_comic.zip', filepath[-1])
|
||||
try:
|
||||
os.remove(tome + '_comic.zip')
|
||||
except FileNotFoundError:
|
||||
# newly temporary created file is not found. It might have been already deleted
|
||||
pass
|
||||
rmtree(tome, True)
|
||||
if GUI:
|
||||
GUI.progressBarTick.emit('tick')
|
||||
@@ -1179,6 +1232,12 @@ def makeBook(source, qtgui=None):
|
||||
os.remove(i.replace('.epub', '.mobi') + '_toclean')
|
||||
if k.path and k.coverSupport:
|
||||
options.covers[filepath.index(i)][0].saveToKindle(k, options.covers[filepath.index(i)][1])
|
||||
if options.delete:
|
||||
if os.path.isfile(source):
|
||||
os.remove(source)
|
||||
elif os.path.isdir(source):
|
||||
rmtree(source)
|
||||
|
||||
return filepath
|
||||
|
||||
|
||||
@@ -1224,7 +1283,8 @@ def makeMOBIWorker(item):
|
||||
if kindlegenErrorCode > 0:
|
||||
break
|
||||
if ":I1036: Mobi file built successfully" in line:
|
||||
output.terminate()
|
||||
output.communicate()
|
||||
break
|
||||
else:
|
||||
# ERROR: EPUB too big
|
||||
kindlegenErrorCode = 23026
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#
|
||||
|
||||
import os
|
||||
import distro
|
||||
from psutil import Popen
|
||||
from shutil import move
|
||||
from subprocess import STDOUT, PIPE
|
||||
@@ -38,8 +39,17 @@ class ComicArchive:
|
||||
self.type = line.rstrip().decode().split(' = ')[1].upper()
|
||||
break
|
||||
process.communicate()
|
||||
if process.returncode != 0:
|
||||
raise OSError('Archive is corrupted or encrypted.')
|
||||
if process.returncode != 0 and distro.id() == 'fedora':
|
||||
process = Popen('unrar l -y -p1 "' + self.filepath + '"', stderr=STDOUT, stdout=PIPE, stdin=PIPE, shell=True)
|
||||
for line in process.stdout:
|
||||
if b'Details: ' in line:
|
||||
self.type = line.rstrip().decode().split(' ')[1].upper()
|
||||
break
|
||||
process.communicate()
|
||||
if process.returncode != 0:
|
||||
raise OSError('Archive is corrupted or encrypted.')
|
||||
elif self.type not in ['7Z', 'RAR', 'RAR5', 'ZIP']:
|
||||
raise OSError('Unsupported archive format.')
|
||||
elif self.type not in ['7Z', 'RAR', 'RAR5', 'ZIP']:
|
||||
raise OSError('Unsupported archive format.')
|
||||
|
||||
@@ -49,8 +59,14 @@ class ComicArchive:
|
||||
process = Popen('7z x -y -xr!__MACOSX -xr!.DS_Store -xr!thumbs.db -xr!Thumbs.db -o"' + targetdir + '" "' +
|
||||
self.filepath + '"', stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=True)
|
||||
process.communicate()
|
||||
if process.returncode != 0:
|
||||
raise OSError('Failed to extract archive.')
|
||||
if process.returncode != 0 and distro.id() == 'fedora':
|
||||
process = Popen('unrar x -y -x__MACOSX -x.DS_Store -xthumbs.db -xThumbs.db "' + self.filepath + '" "' +
|
||||
targetdir + '"', stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=True)
|
||||
process.communicate()
|
||||
if process.returncode != 0:
|
||||
raise OSError('Failed to extract archive.')
|
||||
elif process.returncode != 0:
|
||||
raise OSError('Failed to extract archive. Check if p7zip-rar is installed.')
|
||||
tdir = os.listdir(targetdir)
|
||||
if 'ComicInfo.xml' in tdir:
|
||||
tdir.remove('ComicInfo.xml')
|
||||
|
||||
@@ -115,10 +115,10 @@ class ComicPageParser:
|
||||
self.image = Image.open(os.path.join(source[0], source[1])).convert('RGB')
|
||||
self.color = self.colorCheck()
|
||||
self.fill = self.fillCheck()
|
||||
self.splitCheck()
|
||||
# backwards compatibility for Pillow >9.1.0
|
||||
if not hasattr(Image, 'Resampling'):
|
||||
Image.Resampling = Image
|
||||
self.splitCheck()
|
||||
|
||||
def getImageHistogram(self, image):
|
||||
histogram = image.histogram()
|
||||
@@ -265,6 +265,7 @@ class ComicPage:
|
||||
if self.fill != 'white':
|
||||
flags.append('BlackBackground')
|
||||
if self.opt.forcepng:
|
||||
self.image.info["transparency"] = None
|
||||
self.targetPath += '.png'
|
||||
self.image.save(self.targetPath, 'PNG', optimize=1)
|
||||
else:
|
||||
@@ -350,7 +351,13 @@ class ComicPage:
|
||||
)
|
||||
return bbox
|
||||
|
||||
def cropPageNumber(self, power):
|
||||
def maybeCrop(self, box, minimum):
|
||||
box_area = (box[2] - box[0]) * (box[3] - box[1])
|
||||
image_area = self.image.size[0] * self.image.size[1]
|
||||
if (box_area / image_area) >= minimum:
|
||||
self.image = self.image.crop(box)
|
||||
|
||||
def cropPageNumber(self, power, minimum):
|
||||
if self.fill != 'white':
|
||||
tmptmg = self.image.convert(mode='L')
|
||||
else:
|
||||
@@ -359,16 +366,18 @@ class ComicPage:
|
||||
tmptmg = tmptmg.filter(ImageFilter.MinFilter(size=3))
|
||||
tmptmg = tmptmg.filter(ImageFilter.GaussianBlur(radius=5))
|
||||
tmptmg = tmptmg.point(lambda x: (x >= 16 * power) and x)
|
||||
self.image = self.image.crop(tmptmg.getbbox()) if tmptmg.getbbox() else self.image
|
||||
if tmptmg.getbbox():
|
||||
self.maybeCrop(tmptmg.getbbox(), minimum)
|
||||
|
||||
def cropMargin(self, power):
|
||||
def cropMargin(self, power, minimum):
|
||||
if self.fill != 'white':
|
||||
tmptmg = self.image.convert(mode='L')
|
||||
else:
|
||||
tmptmg = ImageOps.invert(self.image.convert(mode='L'))
|
||||
tmptmg = tmptmg.filter(ImageFilter.GaussianBlur(radius=3))
|
||||
tmptmg = tmptmg.point(lambda x: (x >= 16 * power) and x)
|
||||
self.image = self.image.crop(self.getBoundingBox(tmptmg)) if tmptmg.getbbox() else self.image
|
||||
if tmptmg.getbbox():
|
||||
self.maybeCrop(self.getBoundingBox(tmptmg), minimum)
|
||||
|
||||
|
||||
class Cover:
|
||||
@@ -381,10 +390,10 @@ class Cover:
|
||||
else:
|
||||
self.tomeid = tomeid
|
||||
self.image = Image.open(source)
|
||||
self.process()
|
||||
# backwards compatibility for Pillow >9.1.0
|
||||
if not hasattr(Image, 'Resampling'):
|
||||
Image.Resampling = Image
|
||||
self.process()
|
||||
|
||||
def process(self):
|
||||
self.image = self.image.convert('RGB')
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
PyQt5>=5.6.0
|
||||
Pillow>=5.2.0
|
||||
psutil>=5.0.0
|
||||
python-slugify>=1.2.1,<8.0.0
|
||||
python-slugify>=1.2.1
|
||||
raven>=6.0.0
|
||||
# PyQt5-tools
|
||||
mozjpeg-lossless-optimization
|
||||
mozjpeg-lossless-optimization>=1.1.2
|
||||
distro
|
||||
4
setup.py
4
setup.py
@@ -55,6 +55,7 @@ class BuildBinaryCommand(distutils.cmd.Command):
|
||||
shutil.copy('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/7z', 0o777)
|
||||
# TODO /usr/bin/codesign --force -s "$MACOS_CERTIFICATE_NAME" --options runtime dist/Applications/Kindle\ Comic\ Converter.app -v
|
||||
os.system('appdmg kcc.json dist/KindleComicConverter_osx_' + VERSION + '.dmg')
|
||||
exit(0)
|
||||
elif sys.platform == 'win32':
|
||||
@@ -94,8 +95,9 @@ setuptools.setup(
|
||||
'PyQt5>=5.6.0',
|
||||
'Pillow>=5.2.0',
|
||||
'psutil>=5.0.0',
|
||||
'python-slugify>=1.2.1,<8.0.0',
|
||||
'python-slugify>=1.2.1,<9.0.0',
|
||||
'raven>=6.0.0',
|
||||
'mozjpeg-lossless-optimization>=1.1.2',
|
||||
],
|
||||
classifiers=[],
|
||||
zip_safe=False,
|
||||
|
||||
Reference in New Issue
Block a user