mirror of
https://github.com/ciromattia/kcc
synced 2026-04-15 13:38:46 +00:00
Compare commits
78 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
424118b7cd | ||
|
|
4e45402b8f | ||
|
|
615790c278 | ||
|
|
0d417b8e11 | ||
|
|
6836c20377 | ||
|
|
f75ea6dfe8 | ||
|
|
77afa77d32 | ||
|
|
f73d889b6e | ||
|
|
8e04ccde18 | ||
|
|
cc1e5db0aa | ||
|
|
c5c88095ee | ||
|
|
1318b9c0f2 | ||
|
|
9339abb267 | ||
|
|
154707a412 | ||
|
|
217f571f3d | ||
|
|
531cea88e6 | ||
|
|
a5202458dc | ||
|
|
5902d88d98 | ||
|
|
e7e41715d0 | ||
|
|
62d1c7c488 | ||
|
|
95678adfd6 | ||
|
|
4923dac8f0 | ||
|
|
935727c1db | ||
|
|
b0e38a700a | ||
|
|
23961243b6 | ||
|
|
c98d6179c3 | ||
|
|
37200bdca0 | ||
|
|
0193bcd00a | ||
|
|
0bbe9348a2 | ||
|
|
d16628dc59 | ||
|
|
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 |
@@ -7,8 +7,7 @@ KindleComicConverter.egg-info
|
|||||||
.gitignore
|
.gitignore
|
||||||
.travis.yml
|
.travis.yml
|
||||||
Dockerfile
|
Dockerfile
|
||||||
other
|
|
||||||
venv
|
venv
|
||||||
*.md
|
*.md
|
||||||
LICENSE.txt
|
LICENSE.txt
|
||||||
MANIFEST.in
|
MANIFEST.in
|
||||||
|
|||||||
34
.github/workflows/docker-base-publish.yml
vendored
Normal file
34
.github/workflows/docker-base-publish.yml
vendored
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
name: Docker base
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
push:
|
||||||
|
tags: [ 'docker-base-*' ]
|
||||||
|
|
||||||
|
# Don't trigger if it's just a documentation update
|
||||||
|
paths-ignore:
|
||||||
|
- '**.md'
|
||||||
|
- '**.MD'
|
||||||
|
- '**.yml'
|
||||||
|
- 'docs/**'
|
||||||
|
- 'LICENSE'
|
||||||
|
- '.gitattributes'
|
||||||
|
- '.gitignore'
|
||||||
|
- '.dockerignore'
|
||||||
|
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build_and_push:
|
||||||
|
uses: sdr-enthusiasts/common-github-workflows/.github/workflows/build_and_push_image.yml@main
|
||||||
|
with:
|
||||||
|
docker_build_file: ./Dockerfile-base
|
||||||
|
platform_linux_arm32v7_enabled: true
|
||||||
|
platform_linux_arm64v8_enabled: true
|
||||||
|
platform_linux_amd64_enabled: true
|
||||||
|
push_enabled: true
|
||||||
|
build_nohealthcheck: false
|
||||||
|
ghcr_repo_owner: ${{ github.repository_owner }}
|
||||||
|
ghcr_repo: ${{ github.repository }}
|
||||||
|
build_latest: false
|
||||||
|
secrets:
|
||||||
|
ghcr_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
3
.github/workflows/docker-publish.yml
vendored
3
.github/workflows/docker-publish.yml
vendored
@@ -2,10 +2,7 @@ name: Docker
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
#schedule:
|
|
||||||
# - cron: '39 5 * * *'
|
|
||||||
push:
|
push:
|
||||||
# branches: [ master, pipeline_test, docker_test ]
|
|
||||||
# Publish semver tags as releases.
|
# Publish semver tags as releases.
|
||||||
tags: [ 'v*.*.*' ]
|
tags: [ 'v*.*.*' ]
|
||||||
|
|
||||||
|
|||||||
21
.github/workflows/package-linux.yml
vendored
21
.github/workflows/package-linux.yml
vendored
@@ -7,7 +7,7 @@ on:
|
|||||||
push:
|
push:
|
||||||
tags:
|
tags:
|
||||||
- "v*.*.*"
|
- "v*.*.*"
|
||||||
|
|
||||||
# Don't trigger if it's just a documentation update
|
# Don't trigger if it's just a documentation update
|
||||||
paths-ignore:
|
paths-ignore:
|
||||||
- '**.md'
|
- '**.md'
|
||||||
@@ -23,9 +23,9 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
@@ -34,18 +34,13 @@ jobs:
|
|||||||
- name: Install python dependencies
|
- name: Install python dependencies
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install -y libpng-dev libjpeg-dev p7zip-full python3-pyqt5 squashfs-tools
|
sudo apt-get install -y libpng-dev libjpeg-dev p7zip-full p7zip-rar python3-pyqt5 python3-pip squashfs-tools libfuse2
|
||||||
python -m pip install --upgrade pip setuptools wheel pyinstaller
|
python -m pip install --upgrade pip setuptools wheel certifi pyinstaller PyQt6 --no-binary pyinstaller
|
||||||
pip install -r requirements.txt
|
python -m pip install -r requirements.txt
|
||||||
- name: build binary
|
- name: build binary
|
||||||
run: |
|
run: |
|
||||||
python setup.py build_binary
|
python setup.py build_binary
|
||||||
chmod +x dist/kcc_linux*
|
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
|
# issue with this action, disabled and commented out
|
||||||
# see https://github.com/AppImageCrafters/build-appimage/issues/5
|
# see https://github.com/AppImageCrafters/build-appimage/issues/5
|
||||||
# see https://appimage-builder.readthedocs.io/en/latest/intro/install.html#install-appimagetool
|
# 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
|
appimage-builder --recipe AppImageBuilder.yml --skip-test
|
||||||
env:
|
env:
|
||||||
UPDATE_INFO: gh-releases-zsync|ciromattia|kcc|latest|*x86_64.AppImage.zsync
|
UPDATE_INFO: gh-releases-zsync|ciromattia|kcc|latest|*x86_64.AppImage.zsync
|
||||||
|
|
||||||
- name: upload artifact
|
- name: upload artifact
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: AppImage
|
name: AppImage
|
||||||
path: './*.AppImage*'
|
path: './*.AppImage*'
|
||||||
@@ -78,5 +72,4 @@ jobs:
|
|||||||
files: |
|
files: |
|
||||||
CHANGELOG.md
|
CHANGELOG.md
|
||||||
LICENSE.txt
|
LICENSE.txt
|
||||||
dist/kcc_linux*
|
|
||||||
*.AppImage*
|
*.AppImage*
|
||||||
|
|||||||
45
.github/workflows/package-macos.yml
vendored
45
.github/workflows/package-macos.yml
vendored
@@ -25,7 +25,7 @@ jobs:
|
|||||||
build:
|
build:
|
||||||
runs-on: macos-latest
|
runs-on: macos-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
@@ -33,13 +33,45 @@ jobs:
|
|||||||
cache: 'pip'
|
cache: 'pip'
|
||||||
- name: Install python dependencies
|
- name: Install python dependencies
|
||||||
run: |
|
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
|
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
|
- uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: 16
|
node-version: 16
|
||||||
- run: npm install -g appdmg
|
- run: npm install -g appdmg
|
||||||
- name: build binary
|
- name: build binary
|
||||||
|
# TODO /usr/bin/codesign --force -s "$MACOS_CERTIFICATE_NAME" --options runtime dist/Applications/Kindle\ Comic\ Converter.app -v
|
||||||
run: |
|
run: |
|
||||||
python setup.py build_binary
|
python setup.py build_binary
|
||||||
- name: upload build
|
- name: upload build
|
||||||
@@ -56,4 +88,11 @@ jobs:
|
|||||||
files: |
|
files: |
|
||||||
CHANGELOG.md
|
CHANGELOG.md
|
||||||
LICENSE.txt
|
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@python3-10-pyinstaller-5-3
|
||||||
|
with:
|
||||||
|
path: .
|
||||||
|
spec: ./kcc.spec
|
||||||
|
- name: Package Application
|
||||||
|
uses: JackMcKew/pyinstaller-action-windows@python3-10-pyinstaller-5-3
|
||||||
|
with:
|
||||||
|
path: .
|
||||||
|
spec: ./kcc-c2e.spec
|
||||||
|
- name: Package Application
|
||||||
|
uses: JackMcKew/pyinstaller-action-windows@python3-10-pyinstaller-5-3
|
||||||
|
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:
|
build:
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
python-version: 3.11
|
python-version: 3.11
|
||||||
cache: 'pip'
|
cache: 'pip'
|
||||||
- name: Install python dependencies
|
- name: Install dependencies
|
||||||
|
env:
|
||||||
|
PYINSTALLER_COMPILE_BOOTLOADER: 1
|
||||||
run: |
|
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 -r requirements.txt
|
||||||
|
pip install certifi pyinstaller --no-binary pyinstaller
|
||||||
- name: build binary
|
- name: build binary
|
||||||
run: |
|
run: |
|
||||||
python setup.py build_binary
|
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
|
- amd64
|
||||||
allow_unauthenticated: true
|
allow_unauthenticated: true
|
||||||
sources:
|
sources:
|
||||||
- sourceline: deb http://archive.ubuntu.com/ubuntu focal main restricted
|
- sourceline: deb http://archive.ubuntu.com/ubuntu jammy main restricted
|
||||||
- sourceline: deb http://archive.ubuntu.com/ubuntu focal-updates main restricted
|
- sourceline: deb http://archive.ubuntu.com/ubuntu jammy-updates main restricted
|
||||||
- sourceline: deb http://archive.ubuntu.com/ubuntu focal universe
|
- sourceline: deb http://archive.ubuntu.com/ubuntu jammy universe
|
||||||
- sourceline: deb http://archive.ubuntu.com/ubuntu focal-updates universe
|
- sourceline: deb http://archive.ubuntu.com/ubuntu jammy-updates universe
|
||||||
- sourceline: deb http://archive.ubuntu.com/ubuntu focal multiverse
|
- sourceline: deb http://archive.ubuntu.com/ubuntu jammy multiverse
|
||||||
- sourceline: deb http://archive.ubuntu.com/ubuntu focal-updates multiverse
|
- sourceline: deb http://archive.ubuntu.com/ubuntu jammy-updates multiverse
|
||||||
- sourceline: deb http://archive.ubuntu.com/ubuntu focal-backports main restricted
|
- sourceline: deb http://archive.ubuntu.com/ubuntu jammy-backports main restricted
|
||||||
universe multiverse
|
universe multiverse
|
||||||
- sourceline: deb http://security.ubuntu.com/ubuntu focal-security main restricted
|
- sourceline: deb http://security.ubuntu.com/ubuntu jammy-security main restricted
|
||||||
- sourceline: deb http://security.ubuntu.com/ubuntu focal-security universe
|
- sourceline: deb http://security.ubuntu.com/ubuntu jammy-security universe
|
||||||
- sourceline: deb http://security.ubuntu.com/ubuntu focal-security multiverse
|
- sourceline: deb http://security.ubuntu.com/ubuntu jammy-security multiverse
|
||||||
include:
|
include:
|
||||||
- zlib1g:amd64
|
- libc6:amd64
|
||||||
files:
|
files:
|
||||||
include:
|
include: []
|
||||||
- /lib/x86_64-linux-gnu/libGLX.so.0
|
|
||||||
- /lib/x86_64-linux-gnu/libGLdispatch.so.0
|
|
||||||
- /usr/lib/locale/locale-archive
|
|
||||||
exclude:
|
exclude:
|
||||||
- usr/share/man
|
- usr/share/man
|
||||||
- usr/share/doc/*/README.*
|
- usr/share/doc/*/README.*
|
||||||
|
|||||||
27
CHANGELOG.md
27
CHANGELOG.md
@@ -1,5 +1,32 @@
|
|||||||
# CHANGELOG
|
# CHANGELOG
|
||||||
|
|
||||||
|
|
||||||
|
#### 5.6.2:
|
||||||
|
* build pipeline : drop pypi by @darodi in [#465](https://github.com/ciromattia/kcc/pull/465)
|
||||||
|
* supporting Kindle Previewer by @darodi in [#466](https://github.com/ciromattia/kcc/pull/466)
|
||||||
|
* Bump actions/upload-artifact from 2 to 3 by @dependabot in [#468](https://github.com/ciromattia/kcc/pull/468)
|
||||||
|
* new appImage by @darodi in [#483](https://github.com/ciromattia/kcc/pull/483)
|
||||||
|
* Bump actions/checkout from 2 to 3 by @dependabot in [#484](https://github.com/ciromattia/kcc/pull/484)
|
||||||
|
* supporting Kindle Previewer by @darodi in [#486](https://github.com/ciromattia/kcc/pull/486)
|
||||||
|
* comic2ebook/func: Add a delete option (closes #458) by @Constantin1489 in [#485](https://github.com/ciromattia/kcc/pull/485)
|
||||||
|
* Add command line executables to CI/pipelines by @darodi in [#487](https://github.com/ciromattia/kcc/pull/487)
|
||||||
|
* gui/func: Add a 'delete after conversion' button (closes #458) by @Constantin1489 in [#488](https://github.com/ciromattia/kcc/pull/488)
|
||||||
|
* fix crashes on png transparency by @axu2 in [#494](https://github.com/ciromattia/kcc/pull/494)
|
||||||
|
* Update python-slugify requirement from <8.0.0,>=1.2.1 to >=1.2.1,<9.0.0 by @dependabot in [#473](https://github.com/ciromattia/kcc/pull/473)
|
||||||
|
* Updates GUI text for new Homebrew version by @thatrobotdev in [#491](https://github.com/ciromattia/kcc/pull/491)
|
||||||
|
* Even with EPUB-200MB option selected, created file is above 200MB by @darodi in [#503](https://github.com/ciromattia/kcc/pull/503)
|
||||||
|
* limit kindle scribe image size to (1440, 1920) when using kindlegen by @darodi in [#514](https://github.com/ciromattia/kcc/pull/514)
|
||||||
|
* add 7z to PATH by @axu2 in [#513](https://github.com/ciromattia/kcc/pull/513)
|
||||||
|
* use unrar for fedora only by @darodi in [#515](https://github.com/ciromattia/kcc/pull/515)
|
||||||
|
|
||||||
|
|
||||||
|
#### 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:
|
#### 5.6.0:
|
||||||
* Fix Docker 7z missing [darodi/kcc#31](https://github.com/darodi/kcc/issues/31), thanks [@darodi](https://github.com/darodi)
|
* 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)
|
* update to python 3.11, thanks [@darodi](https://github.com/darodi)
|
||||||
|
|||||||
152
Dockerfile
152
Dockerfile
@@ -1,147 +1,5 @@
|
|||||||
FROM --platform=linux/amd64 python:3.11-slim-buster as compile-amd64
|
|
||||||
ARG TARGETOS
|
|
||||||
ARG TARGETARCH
|
|
||||||
ARG TARGETVARIANT
|
|
||||||
RUN echo "I'm building for $TARGETOS/$TARGETARCH/$TARGETVARIANT"
|
|
||||||
|
|
||||||
|
|
||||||
COPY requirements.txt /opt/kcc/
|
|
||||||
ENV PATH="/opt/venv/bin:$PATH"
|
|
||||||
RUN DEBIAN_FRONTEND=noninteractive apt-get update -y && apt-get -yq upgrade && \
|
|
||||||
apt-get install -y libpng-dev libjpeg-dev p7zip-full unrar-free libgl1 python3-pyqt5 && \
|
|
||||||
python -m pip install --upgrade pip && \
|
|
||||||
python -m venv /opt/venv && \
|
|
||||||
python -m pip install -r /opt/kcc/requirements.txt
|
|
||||||
|
|
||||||
|
|
||||||
######################################################################################
|
|
||||||
|
|
||||||
FROM --platform=linux/arm64 python:3.11-slim-buster as compile-arm64
|
|
||||||
ARG TARGETOS
|
|
||||||
ARG TARGETARCH
|
|
||||||
ARG TARGETVARIANT
|
|
||||||
RUN echo "I'm building for $TARGETOS/$TARGETARCH/$TARGETVARIANT"
|
|
||||||
|
|
||||||
ENV LC_ALL=C.UTF-8 \
|
|
||||||
LANG=C.UTF-8 \
|
|
||||||
LANGUAGE=en_US:en
|
|
||||||
|
|
||||||
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
|
|
||||||
|
|
||||||
RUN set -x && \
|
|
||||||
TEMP_PACKAGES=() && \
|
|
||||||
KEPT_PACKAGES=() && \
|
|
||||||
# Packages only required during build
|
|
||||||
TEMP_PACKAGES+=(build-essential) && \
|
|
||||||
TEMP_PACKAGES+=(cmake) && \
|
|
||||||
TEMP_PACKAGES+=(libfreetype6-dev) && \
|
|
||||||
TEMP_PACKAGES+=(libfontconfig1-dev) && \
|
|
||||||
TEMP_PACKAGES+=(libpng-dev) && \
|
|
||||||
TEMP_PACKAGES+=(libjpeg-dev) && \
|
|
||||||
TEMP_PACKAGES+=(libssl-dev) && \
|
|
||||||
TEMP_PACKAGES+=(libxft-dev) && \
|
|
||||||
TEMP_PACKAGES+=(make) && \
|
|
||||||
TEMP_PACKAGES+=(python3-dev) && \
|
|
||||||
TEMP_PACKAGES+=(python3-setuptools) && \
|
|
||||||
TEMP_PACKAGES+=(python3-wheel) && \
|
|
||||||
# Packages kept in the image
|
|
||||||
KEPT_PACKAGES+=(bash) && \
|
|
||||||
KEPT_PACKAGES+=(ca-certificates) && \
|
|
||||||
KEPT_PACKAGES+=(chrpath) && \
|
|
||||||
KEPT_PACKAGES+=(locales) && \
|
|
||||||
KEPT_PACKAGES+=(locales-all) && \
|
|
||||||
KEPT_PACKAGES+=(libfreetype6) && \
|
|
||||||
KEPT_PACKAGES+=(libfontconfig1) && \
|
|
||||||
KEPT_PACKAGES+=(p7zip-full) && \
|
|
||||||
KEPT_PACKAGES+=(python3) && \
|
|
||||||
KEPT_PACKAGES+=(python3-pip) && \
|
|
||||||
KEPT_PACKAGES+=(python-pyqt5) && \
|
|
||||||
KEPT_PACKAGES+=(qt5-default) && \
|
|
||||||
KEPT_PACKAGES+=(unrar-free) && \
|
|
||||||
# Install packages
|
|
||||||
DEBIAN_FRONTEND=noninteractive apt-get update -y && apt-get -yq upgrade && \
|
|
||||||
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
|
|
||||||
${KEPT_PACKAGES[@]} \
|
|
||||||
${TEMP_PACKAGES[@]} \
|
|
||||||
&& \
|
|
||||||
# Install required python modules
|
|
||||||
python -m pip install --upgrade pip && \
|
|
||||||
# python -m pip install -r /opt/kcc/requirements.txt && \
|
|
||||||
python -m venv /opt/venv && \
|
|
||||||
python -m pip install --upgrade pillow python-slugify psutil raven mozjpeg-lossless-optimization
|
|
||||||
|
|
||||||
|
|
||||||
######################################################################################
|
|
||||||
|
|
||||||
FROM --platform=linux/arm/v7 python:3.11-slim-buster as compile-armv7
|
|
||||||
ARG TARGETOS
|
|
||||||
ARG TARGETARCH
|
|
||||||
ARG TARGETVARIANT
|
|
||||||
RUN echo "I'm building for $TARGETOS/$TARGETARCH/$TARGETVARIANT"
|
|
||||||
|
|
||||||
ENV LC_ALL=C.UTF-8 \
|
|
||||||
LANG=C.UTF-8 \
|
|
||||||
LANGUAGE=en_US:en
|
|
||||||
|
|
||||||
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
|
|
||||||
|
|
||||||
RUN set -x && \
|
|
||||||
TEMP_PACKAGES=() && \
|
|
||||||
KEPT_PACKAGES=() && \
|
|
||||||
# Packages only required during build
|
|
||||||
TEMP_PACKAGES+=(build-essential) && \
|
|
||||||
TEMP_PACKAGES+=(cmake) && \
|
|
||||||
TEMP_PACKAGES+=(libffi-dev) && \
|
|
||||||
TEMP_PACKAGES+=(libfreetype6-dev) && \
|
|
||||||
TEMP_PACKAGES+=(libfontconfig1-dev) && \
|
|
||||||
TEMP_PACKAGES+=(libpng-dev) && \
|
|
||||||
TEMP_PACKAGES+=(libjpeg-dev) && \
|
|
||||||
TEMP_PACKAGES+=(libssl-dev) && \
|
|
||||||
TEMP_PACKAGES+=(libxft-dev) && \
|
|
||||||
TEMP_PACKAGES+=(make) && \
|
|
||||||
TEMP_PACKAGES+=(python3-dev) && \
|
|
||||||
TEMP_PACKAGES+=(python3-setuptools) && \
|
|
||||||
TEMP_PACKAGES+=(python3-wheel) && \
|
|
||||||
# Packages kept in the image
|
|
||||||
KEPT_PACKAGES+=(bash) && \
|
|
||||||
KEPT_PACKAGES+=(ca-certificates) && \
|
|
||||||
KEPT_PACKAGES+=(chrpath) && \
|
|
||||||
KEPT_PACKAGES+=(locales) && \
|
|
||||||
KEPT_PACKAGES+=(locales-all) && \
|
|
||||||
KEPT_PACKAGES+=(libfreetype6) && \
|
|
||||||
KEPT_PACKAGES+=(libfontconfig1) && \
|
|
||||||
KEPT_PACKAGES+=(p7zip-full) && \
|
|
||||||
KEPT_PACKAGES+=(python3) && \
|
|
||||||
KEPT_PACKAGES+=(python3-pip) && \
|
|
||||||
KEPT_PACKAGES+=(python-pyqt5) && \
|
|
||||||
KEPT_PACKAGES+=(qt5-default) && \
|
|
||||||
KEPT_PACKAGES+=(unrar-free) && \
|
|
||||||
# Install packages
|
|
||||||
DEBIAN_FRONTEND=noninteractive apt-get update -y && apt-get -yq upgrade && \
|
|
||||||
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
|
|
||||||
${KEPT_PACKAGES[@]} \
|
|
||||||
${TEMP_PACKAGES[@]} \
|
|
||||||
&& \
|
|
||||||
# Install required python modules
|
|
||||||
python -m pip install --upgrade pip && \
|
|
||||||
# python -m pip install -r /opt/kcc/requirements.txt && \
|
|
||||||
python -m venv /opt/venv && \
|
|
||||||
python -m pip install --upgrade pillow python-slugify psutil raven mozjpeg-lossless-optimization
|
|
||||||
|
|
||||||
|
|
||||||
######################################################################################
|
|
||||||
FROM --platform=linux/amd64 python:3.11-slim-buster as build-amd64
|
|
||||||
COPY --from=compile-amd64 /opt/venv /opt/venv
|
|
||||||
|
|
||||||
FROM --platform=linux/arm64 python:3.11-slim-buster as build-arm64
|
|
||||||
COPY --from=compile-arm64 /opt/venv /opt/venv
|
|
||||||
|
|
||||||
FROM --platform=linux/arm/v7 python:3.11-slim-buster as build-armv7
|
|
||||||
COPY --from=compile-armv7 /opt/venv /opt/venv
|
|
||||||
######################################################################################
|
|
||||||
|
|
||||||
# Select final stage based on TARGETARCH ARG
|
# Select final stage based on TARGETARCH ARG
|
||||||
FROM build-${TARGETARCH}${TARGETVARIANT}
|
FROM ghcr.io/ciromattia/kcc:docker-base-20230514
|
||||||
LABEL com.kcc.name="Kindle Comic Converter"
|
LABEL com.kcc.name="Kindle Comic Converter"
|
||||||
LABEL com.kcc.author="Ciro Mattia Gonano, Paweł Jastrzębski and Darodi"
|
LABEL com.kcc.author="Ciro Mattia Gonano, Paweł Jastrzębski and Darodi"
|
||||||
LABEL org.opencontainers.image.description='Kindle Comic Converter'
|
LABEL org.opencontainers.image.description='Kindle Comic Converter'
|
||||||
@@ -154,14 +12,8 @@ LABEL org.opencontainers.image.vendor='ciromattia'
|
|||||||
LABEL org.opencontainers.image.licenses='ISC'
|
LABEL org.opencontainers.image.licenses='ISC'
|
||||||
LABEL org.opencontainers.image.title="Kindle Comic Converter"
|
LABEL org.opencontainers.image.title="Kindle Comic Converter"
|
||||||
|
|
||||||
|
|
||||||
ENV PATH="/opt/venv/bin:$PATH"
|
|
||||||
WORKDIR /app
|
|
||||||
COPY . /opt/kcc
|
COPY . /opt/kcc
|
||||||
RUN DEBIAN_FRONTEND=noninteractive apt-get update -y && apt-get -yq upgrade && \
|
RUN cat /opt/kcc/kindlecomicconverter/__init__.py | grep version | awk '{print $3}' | sed "s/'//g" > /IMAGE_VERSION
|
||||||
apt-get install -y p7zip-full unrar-free && \
|
|
||||||
ln -s /app/kindlegen /bin/kindlegen && \
|
|
||||||
cat /opt/kcc/kindlecomicconverter/__init__.py | grep version | awk '{print $3}' | sed "s/'//g" > /IMAGE_VERSION
|
|
||||||
|
|
||||||
ENTRYPOINT ["/opt/kcc/kcc-c2e.py"]
|
ENTRYPOINT ["/opt/kcc/kcc-c2e.py"]
|
||||||
CMD ["-h"]
|
CMD ["-h"]
|
||||||
162
Dockerfile-base
Normal file
162
Dockerfile-base
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
FROM --platform=linux/amd64 python:3.11-slim-bullseye as compile-amd64
|
||||||
|
ARG TARGETOS
|
||||||
|
ARG TARGETARCH
|
||||||
|
ARG TARGETVARIANT
|
||||||
|
RUN echo "I'm building for $TARGETOS/$TARGETARCH/$TARGETVARIANT"
|
||||||
|
|
||||||
|
|
||||||
|
COPY requirements.txt /opt/kcc/
|
||||||
|
ENV PATH="/opt/venv/bin:$PATH"
|
||||||
|
RUN DEBIAN_FRONTEND=noninteractive apt-get update -y && apt-get -yq upgrade && \
|
||||||
|
apt-get install -y libpng-dev libjpeg-dev p7zip-full unrar-free libgl1 python3-pyqt5 && \
|
||||||
|
python -m pip install --upgrade pip && \
|
||||||
|
python -m venv /opt/venv && \
|
||||||
|
python -m pip install -r /opt/kcc/requirements.txt
|
||||||
|
|
||||||
|
|
||||||
|
######################################################################################
|
||||||
|
|
||||||
|
FROM --platform=linux/arm64 python:3.11-slim-bullseye as compile-arm64
|
||||||
|
ARG TARGETOS
|
||||||
|
ARG TARGETARCH
|
||||||
|
ARG TARGETVARIANT
|
||||||
|
RUN echo "I'm building for $TARGETOS/$TARGETARCH/$TARGETVARIANT"
|
||||||
|
|
||||||
|
ENV LC_ALL=C.UTF-8 \
|
||||||
|
LANG=C.UTF-8 \
|
||||||
|
LANGUAGE=en_US:en
|
||||||
|
|
||||||
|
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
|
||||||
|
|
||||||
|
RUN set -x && \
|
||||||
|
TEMP_PACKAGES=() && \
|
||||||
|
KEPT_PACKAGES=() && \
|
||||||
|
# Packages only required during build
|
||||||
|
TEMP_PACKAGES+=(build-essential) && \
|
||||||
|
TEMP_PACKAGES+=(cmake) && \
|
||||||
|
TEMP_PACKAGES+=(libfreetype6-dev) && \
|
||||||
|
TEMP_PACKAGES+=(libfontconfig1-dev) && \
|
||||||
|
TEMP_PACKAGES+=(libpng-dev) && \
|
||||||
|
TEMP_PACKAGES+=(libjpeg-dev) && \
|
||||||
|
TEMP_PACKAGES+=(libssl-dev) && \
|
||||||
|
TEMP_PACKAGES+=(libxft-dev) && \
|
||||||
|
TEMP_PACKAGES+=(make) && \
|
||||||
|
TEMP_PACKAGES+=(python3-dev) && \
|
||||||
|
TEMP_PACKAGES+=(python3-setuptools) && \
|
||||||
|
TEMP_PACKAGES+=(python3-wheel) && \
|
||||||
|
# Packages kept in the image
|
||||||
|
KEPT_PACKAGES+=(bash) && \
|
||||||
|
KEPT_PACKAGES+=(ca-certificates) && \
|
||||||
|
KEPT_PACKAGES+=(chrpath) && \
|
||||||
|
KEPT_PACKAGES+=(locales) && \
|
||||||
|
KEPT_PACKAGES+=(locales-all) && \
|
||||||
|
KEPT_PACKAGES+=(libfreetype6) && \
|
||||||
|
KEPT_PACKAGES+=(libfontconfig1) && \
|
||||||
|
KEPT_PACKAGES+=(p7zip-full) && \
|
||||||
|
KEPT_PACKAGES+=(python3) && \
|
||||||
|
KEPT_PACKAGES+=(python3-pip) && \
|
||||||
|
KEPT_PACKAGES+=(python3-pyqt5) && \
|
||||||
|
KEPT_PACKAGES+=(unrar-free) && \
|
||||||
|
# Install packages
|
||||||
|
DEBIAN_FRONTEND=noninteractive apt-get update -y && apt-get -yq upgrade && \
|
||||||
|
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
|
||||||
|
${KEPT_PACKAGES[@]} \
|
||||||
|
${TEMP_PACKAGES[@]} \
|
||||||
|
&& \
|
||||||
|
# Install required python modules
|
||||||
|
python -m pip install --upgrade pip && \
|
||||||
|
# python -m pip install -r /opt/kcc/requirements.txt && \
|
||||||
|
python -m venv /opt/venv && \
|
||||||
|
python -m pip install --upgrade pillow python-slugify psutil raven mozjpeg-lossless-optimization
|
||||||
|
|
||||||
|
|
||||||
|
######################################################################################
|
||||||
|
|
||||||
|
FROM --platform=linux/arm/v7 python:3.11-slim-bullseye as compile-armv7
|
||||||
|
ARG TARGETOS
|
||||||
|
ARG TARGETARCH
|
||||||
|
ARG TARGETVARIANT
|
||||||
|
RUN echo "I'm building for $TARGETOS/$TARGETARCH/$TARGETVARIANT"
|
||||||
|
|
||||||
|
ENV LC_ALL=C.UTF-8 \
|
||||||
|
LANG=C.UTF-8 \
|
||||||
|
LANGUAGE=en_US:en
|
||||||
|
|
||||||
|
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
|
||||||
|
|
||||||
|
RUN set -x && \
|
||||||
|
TEMP_PACKAGES=() && \
|
||||||
|
KEPT_PACKAGES=() && \
|
||||||
|
# Packages only required during build
|
||||||
|
TEMP_PACKAGES+=(build-essential) && \
|
||||||
|
TEMP_PACKAGES+=(cmake) && \
|
||||||
|
TEMP_PACKAGES+=(libffi-dev) && \
|
||||||
|
TEMP_PACKAGES+=(libfreetype6-dev) && \
|
||||||
|
TEMP_PACKAGES+=(libfontconfig1-dev) && \
|
||||||
|
TEMP_PACKAGES+=(libpng-dev) && \
|
||||||
|
TEMP_PACKAGES+=(libjpeg-dev) && \
|
||||||
|
TEMP_PACKAGES+=(libssl-dev) && \
|
||||||
|
TEMP_PACKAGES+=(libxft-dev) && \
|
||||||
|
TEMP_PACKAGES+=(make) && \
|
||||||
|
TEMP_PACKAGES+=(python3-dev) && \
|
||||||
|
TEMP_PACKAGES+=(python3-setuptools) && \
|
||||||
|
TEMP_PACKAGES+=(python3-wheel) && \
|
||||||
|
# Packages kept in the image
|
||||||
|
KEPT_PACKAGES+=(bash) && \
|
||||||
|
KEPT_PACKAGES+=(ca-certificates) && \
|
||||||
|
KEPT_PACKAGES+=(chrpath) && \
|
||||||
|
KEPT_PACKAGES+=(locales) && \
|
||||||
|
KEPT_PACKAGES+=(locales-all) && \
|
||||||
|
KEPT_PACKAGES+=(libfreetype6) && \
|
||||||
|
KEPT_PACKAGES+=(libfontconfig1) && \
|
||||||
|
KEPT_PACKAGES+=(p7zip-full) && \
|
||||||
|
KEPT_PACKAGES+=(python3) && \
|
||||||
|
KEPT_PACKAGES+=(python3-pip) && \
|
||||||
|
KEPT_PACKAGES+=(python3-pyqt5) && \
|
||||||
|
KEPT_PACKAGES+=(unrar-free) && \
|
||||||
|
# Install packages
|
||||||
|
DEBIAN_FRONTEND=noninteractive apt-get update -y && apt-get -yq upgrade && \
|
||||||
|
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
|
||||||
|
${KEPT_PACKAGES[@]} \
|
||||||
|
${TEMP_PACKAGES[@]} \
|
||||||
|
&& \
|
||||||
|
# Install required python modules
|
||||||
|
python -m pip install --upgrade pip && \
|
||||||
|
# python -m pip install -r /opt/kcc/requirements.txt && \
|
||||||
|
python -m venv /opt/venv && \
|
||||||
|
python -m pip install --upgrade pillow python-slugify psutil raven mozjpeg-lossless-optimization
|
||||||
|
|
||||||
|
|
||||||
|
######################################################################################
|
||||||
|
FROM --platform=linux/amd64 python:3.11-slim-bullseye as build-amd64
|
||||||
|
COPY --from=compile-amd64 /opt/venv /opt/venv
|
||||||
|
|
||||||
|
FROM --platform=linux/arm64 python:3.11-slim-bullseye as build-arm64
|
||||||
|
COPY --from=compile-arm64 /opt/venv /opt/venv
|
||||||
|
|
||||||
|
FROM --platform=linux/arm/v7 python:3.11-slim-bullseye as build-armv7
|
||||||
|
COPY --from=compile-armv7 /opt/venv /opt/venv
|
||||||
|
######################################################################################
|
||||||
|
|
||||||
|
# Select final stage based on TARGETARCH ARG
|
||||||
|
FROM build-${TARGETARCH}${TARGETVARIANT}
|
||||||
|
LABEL com.kcc.name="Kindle Comic Converter base image"
|
||||||
|
LABEL com.kcc.author="Ciro Mattia Gonano, Paweł Jastrzębski and Darodi"
|
||||||
|
LABEL org.opencontainers.image.description='Kindle Comic Converter base image'
|
||||||
|
LABEL org.opencontainers.image.documentation='https://github.com/ciromattia/kcc'
|
||||||
|
LABEL org.opencontainers.image.source='https://github.com/ciromattia/kcc'
|
||||||
|
LABEL org.opencontainers.image.authors='darodi'
|
||||||
|
LABEL org.opencontainers.image.url='https://github.com/ciromattia/kcc'
|
||||||
|
LABEL org.opencontainers.image.documentation='https://github.com/ciromattia/kcc'
|
||||||
|
LABEL org.opencontainers.image.vendor='ciromattia'
|
||||||
|
LABEL org.opencontainers.image.licenses='ISC'
|
||||||
|
LABEL org.opencontainers.image.title="Kindle Comic Converter"
|
||||||
|
|
||||||
|
|
||||||
|
ENV PATH="/opt/venv/bin:$PATH"
|
||||||
|
WORKDIR /app
|
||||||
|
RUN DEBIAN_FRONTEND=noninteractive apt-get update -y && apt-get -yq upgrade && \
|
||||||
|
apt-get install -y p7zip-full unrar-free && \
|
||||||
|
ln -s /app/kindlegen /bin/kindlegen && \
|
||||||
|
echo docker-base-20230514 > /IMAGE_VERSION
|
||||||
|
|
||||||
358
README.md
358
README.md
@@ -1,16 +1,10 @@
|
|||||||
# KCC
|
# 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://github.com/ciromattia/kcc/releases)
|
||||||
[](https://pypi.python.org/pypi/KindleComicConverter)
|
[](https://github.com/ciromattia/kcc/pkgs/container/kcc)
|
||||||
[](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
|
||||||
@@ -38,138 +32,20 @@ If you find **KCC** valuable you can consider donating to the authors:
|
|||||||
|
|
||||||
## INSTALLATION
|
## INSTALLATION
|
||||||
|
|
||||||
|
### DOWNLOADS
|
||||||
|
|
||||||
### BINARY RELEASES
|
|
||||||
You can find the latest binary at the following link:
|
|
||||||
|
|
||||||
- **https://github.com/ciromattia/kcc/releases**
|
- **https://github.com/ciromattia/kcc/releases**
|
||||||
|
|
||||||
|
Click on **Assets** of the latest release.
|
||||||
|
|
||||||
~~- **[Windows](http://kcc.iosphe.re/Windows/) (64-bit only)**~~
|
You probably want either
|
||||||
~~- **[macOS](http://kcc.iosphe.re/OSX/) (10.14+)**~~
|
- `kcc_*.*.*.exe` (Windows)
|
||||||
~~- **Linux:** Currently unavailable.~~
|
- `KindleComicConverter_osx_*.*.*.dmg` (Mac)
|
||||||
|
|
||||||
|
Installation Wiki: https://github.com/ciromattia/kcc/wiki/Installation
|
||||||
|
|
||||||
|
- flatpak : https://flathub.org/apps/details/io.github.ciromattia.kcc
|
||||||
#### MacOS installation
|
- Docker: https://github.com/ciromattia/kcc/pkgs/container/kcc
|
||||||
##### 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
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
### 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:
|
||||||
@@ -181,92 +57,28 @@ 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)
|
- [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:
|
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
|
#### Optional dependencies
|
||||||
- Qt platform integration plugin for Deepin Desktop Environment
|
- Qt platform integration plugin for Deepin Desktop Environment
|
||||||
```bash
|
```bash
|
||||||
$ sudo apt-get install qt5dxcb-plugin
|
$ 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)
|
- KindleGen ~~[(deprecated link)](http://www.amazon.com/gp/feature.html?ie=UTF8&docId=1000765211)~~ v2.9+ (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.
|
- should be placed in a directory reachable by your _PATH_ or in _KCC_ directory
|
||||||
|
- `KindleGen` can be found in [Kindle Previewer](https://www.amazon.com/Kindle-Previewer/b?ie=UTF8&node=21381691011)
|
||||||
|
- `KindleGen` can be also be found in [Kindle Comic Creator](https://www.amazon.com/b?node=23496309011)
|
||||||
- [7z](http://www.7-zip.org/download.html) *(For CBZ/ZIP, CBR/RAR, 7z/CB7 support)*
|
- [7z](http://www.7-zip.org/download.html) *(For CBZ/ZIP, CBR/RAR, 7z/CB7 support)*
|
||||||
|
- Unrar (no rar in 7z on Fedora)
|
||||||
### 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'
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -286,6 +98,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.
|
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 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:
|
### Profiles:
|
||||||
|
|
||||||
@@ -321,85 +137,81 @@ CLI version of **KCC** is intended for power users. It allows using options that
|
|||||||
### Standalone `kcc-c2e.py` usage:
|
### Standalone `kcc-c2e.py` usage:
|
||||||
|
|
||||||
```
|
```
|
||||||
Usage: kcc-c2e [options] comic_file|comic_folder
|
usage: kcc-c2e [options] [input]
|
||||||
|
|
||||||
Options:
|
MANDATORY:
|
||||||
MAIN:
|
input Full path to comic folder or file(s) to be processed.
|
||||||
-p PROFILE, --profile=PROFILE
|
|
||||||
Device profile (Available options: K1, K2, K34, K578,
|
|
||||||
KDX, KPW, KPW5, KV, KO, K11, KS, KoMT, KoG, KoGHD,
|
|
||||||
KoA, KoAHD, KoAH2O, KoAO, KoN, KoC, KoL, KoF, KoS,
|
|
||||||
KoE) [Default=KV]
|
|
||||||
-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
|
|
||||||
-w, --webtoon Webtoon processing mode
|
|
||||||
--targetsize=TARGETSIZE
|
|
||||||
the maximal size of output file in MB. [Default=100MB
|
|
||||||
for webtoon and 400MB for others]
|
|
||||||
|
|
||||||
OUTPUT SETTINGS:
|
MAIN:
|
||||||
-o OUTPUT, --output=OUTPUT
|
-p PROFILE, --profile PROFILE
|
||||||
Output generated file to specified directory or file
|
Device profile (Available options: K1, K2, K34, K578, KDX, KPW, KPW5, KV, KO, K11, KS, KoMT, KoG, KoGHD, KoA, KoAHD, KoAH2O, KoAO, KoN, KoC, KoL, KoF, KoS, KoE) [Default=KV]
|
||||||
-t TITLE, --title=TITLE
|
-m, --manga-style Manga style (right-to-left reading and splitting)
|
||||||
Comic title [Default=filename or directory name]
|
-q, --hq Try to increase the quality of magnification
|
||||||
-f FORMAT, --format=FORMAT
|
-2, --two-panel Display two not four panels in Panel View mode
|
||||||
Output format (Available options: Auto, MOBI, EPUB,
|
-w, --webtoon Webtoon processing mode
|
||||||
CBZ, KFX, MOBI+EPUB) [Default=Auto]
|
--ts TARGETSIZE, --targetsize TARGETSIZE
|
||||||
-b BATCHSPLIT, --batchsplit=BATCHSPLIT
|
the maximal size of output file in MB. [Default=100MB for webtoon and 400MB for others]
|
||||||
Split output into multiple files. 0: Don't split 1:
|
|
||||||
Automatic mode 2: Consider every subdirectory as
|
|
||||||
separate volume [Default=0]
|
|
||||||
|
|
||||||
PROCESSING:
|
PROCESSING:
|
||||||
-n, --noprocessing Do not modify image and ignore any profil or
|
-n, --noprocessing Do not modify image and ignore any profil or processing option
|
||||||
processing option
|
-u, --upscale Resize images smaller than device's resolution
|
||||||
-u, --upscale Resize images smaller than device's resolution
|
-s, --stretch Stretch images to device's resolution
|
||||||
-s, --stretch Stretch images to device's resolution
|
-r SPLITTER, --splitter SPLITTER
|
||||||
-r SPLITTER, --splitter=SPLITTER
|
Double page parsing mode. 0: Split 1: Rotate 2: Both [Default=0]
|
||||||
Double page parsing mode. 0: Split 1: Rotate 2: Both
|
-g GAMMA, --gamma GAMMA
|
||||||
[Default=0]
|
Apply gamma correction to linearize the image [Default=Auto]
|
||||||
-g GAMMA, --gamma=GAMMA
|
-c CROPPING, --cropping CROPPING
|
||||||
Apply gamma correction to linearize the image
|
Set cropping mode. 0: Disabled 1: Margins 2: Margins + page numbers [Default=2]
|
||||||
[Default=Auto]
|
--cp CROPPINGP, --croppingpower CROPPINGP
|
||||||
-c CROPPING, --cropping=CROPPING
|
|
||||||
Set cropping mode. 0: Disabled 1: Margins 2: Margins +
|
|
||||||
page numbers [Default=2]
|
|
||||||
--cp=CROPPINGP, --croppingpower=CROPPINGP
|
|
||||||
Set cropping power [Default=1.0]
|
Set cropping power [Default=1.0]
|
||||||
--blackborders Disable autodetection and force black borders
|
--cm CROPPINGM, --croppingminimum CROPPINGM
|
||||||
--whiteborders Disable autodetection and force white borders
|
Set cropping minimum area ratio [Default=0.0]
|
||||||
--forcecolor Don't convert images to grayscale
|
--blackborders Disable autodetection and force black borders
|
||||||
--forcepng Create PNG files instead JPEG
|
--whiteborders Disable autodetection and force white borders
|
||||||
--mozjpeg Create JPEG files using mozJpeg
|
--forcecolor Don't convert images to grayscale
|
||||||
--maximizestrips Turn 1x4 strips to 2x2 strips
|
--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:
|
OUTPUT SETTINGS:
|
||||||
--customwidth=CUSTOMWIDTH
|
-o OUTPUT, --output OUTPUT
|
||||||
|
Output generated file to specified directory or file
|
||||||
|
-t TITLE, --title TITLE
|
||||||
|
Comic title [Default=filename or directory name]
|
||||||
|
-f FORMAT, --format FORMAT
|
||||||
|
Output format (Available options: Auto, MOBI, EPUB, CBZ, KFX, MOBI+EPUB) [Default=Auto]
|
||||||
|
-b BATCHSPLIT, --batchsplit BATCHSPLIT
|
||||||
|
Split output into multiple files. 0: Don't split 1: Automatic mode 2: Consider every subdirectory as separate volume [Default=0]
|
||||||
|
|
||||||
|
CUSTOM PROFILE:
|
||||||
|
--customwidth CUSTOMWIDTH
|
||||||
Replace screen width provided by device profile
|
Replace screen width provided by device profile
|
||||||
--customheight=CUSTOMHEIGHT
|
--customheight CUSTOMHEIGHT
|
||||||
Replace screen height provided by device profile
|
Replace screen height provided by device profile
|
||||||
|
|
||||||
OTHER:
|
OTHER:
|
||||||
-h, --help Show this help message and exit
|
-h, --help Show this help message and exit
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Standalone `kcc-c2p.py` usage:
|
### Standalone `kcc-c2p.py` usage:
|
||||||
|
|
||||||
```
|
```
|
||||||
Usage: kcc-c2p [options] comic_folder
|
usage: kcc-c2p [options] [input]
|
||||||
|
|
||||||
Options:
|
MANDATORY:
|
||||||
MANDATORY:
|
input Full path to comic folder(s) to be processed. Separate multiple inputs with spaces.
|
||||||
-y HEIGHT, --height=HEIGHT
|
|
||||||
|
MAIN:
|
||||||
|
-y HEIGHT, --height HEIGHT
|
||||||
Height of the target device screen
|
Height of the target device screen
|
||||||
-i, --in-place Overwrite source directory
|
-i, --in-place Overwrite source directory
|
||||||
-m, --merge Combine every directory into a single image before
|
-m, --merge Combine every directory into a single image before splitting
|
||||||
splitting
|
|
||||||
|
|
||||||
OTHER:
|
OTHER:
|
||||||
-d, --debug Create debug file for every split 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
|
||||||
```
|
```
|
||||||
|
|
||||||
## CREDITS
|
## CREDITS
|
||||||
|
|||||||
15
environment.yml
Normal file
15
environment.yml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
name: kcc
|
||||||
|
channels:
|
||||||
|
- conda-forge
|
||||||
|
- defaults
|
||||||
|
dependencies:
|
||||||
|
- python=3.11
|
||||||
|
- Pillow>=5.2.0
|
||||||
|
- psutil>=5.0.0
|
||||||
|
- python-slugify>=1.2.1
|
||||||
|
- raven>=6.0.0
|
||||||
|
- distro
|
||||||
|
- pip
|
||||||
|
- pip:
|
||||||
|
- mozjpeg-lossless-optimization>=1.1.2
|
||||||
|
- PyQt5>=5.6.0
|
||||||
15
gui/KCC.ui
15
gui/KCC.ui
@@ -175,10 +175,20 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</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">
|
<item row="4" column="2">
|
||||||
<widget class="QCheckBox" name="disableProcessingBox">
|
<widget class="QCheckBox" name="disableProcessingBox">
|
||||||
<property name="toolTip">
|
<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>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Disable processing</string>
|
<string>Disable processing</string>
|
||||||
@@ -257,7 +267,7 @@
|
|||||||
<item>
|
<item>
|
||||||
<widget class="QSlider" name="croppingPowerSlider">
|
<widget class="QSlider" name="croppingPowerSlider">
|
||||||
<property name="maximum">
|
<property name="maximum">
|
||||||
<number>10</number>
|
<number>200</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="singleStep">
|
<property name="singleStep">
|
||||||
<number>1</number>
|
<number>1</number>
|
||||||
@@ -600,6 +610,7 @@
|
|||||||
<tabstop>croppingBox</tabstop>
|
<tabstop>croppingBox</tabstop>
|
||||||
<tabstop>mozJpegBox</tabstop>
|
<tabstop>mozJpegBox</tabstop>
|
||||||
<tabstop>maximizeStrips</tabstop>
|
<tabstop>maximizeStrips</tabstop>
|
||||||
|
<tabstop>deleteBox</tabstop>
|
||||||
<tabstop>disableProcessingBox</tabstop>
|
<tabstop>disableProcessingBox</tabstop>
|
||||||
<tabstop>editorButton</tabstop>
|
<tabstop>editorButton</tabstop>
|
||||||
<tabstop>wikiButton</tabstop>
|
<tabstop>wikiButton</tabstop>
|
||||||
|
|||||||
@@ -19,8 +19,9 @@
|
|||||||
# PERFORMANCE OF THIS SOFTWARE.
|
# PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
if sys.version_info[0] != 3:
|
|
||||||
print('ERROR: This is Python 3 script!')
|
if sys.version_info < (3, 8, 0):
|
||||||
|
print('ERROR: This is a Python 3.8+ script!')
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
from multiprocessing import freeze_support, set_start_method
|
from multiprocessing import freeze_support, set_start_method
|
||||||
|
|||||||
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')
|
||||||
@@ -19,8 +19,9 @@
|
|||||||
# PERFORMANCE OF THIS SOFTWARE.
|
# PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
if sys.version_info[0] != 3:
|
|
||||||
print('ERROR: This is Python 3 script!')
|
if sys.version_info < (3, 8, 0):
|
||||||
|
print('ERROR: This is a Python 3.8+ script!')
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
from multiprocessing import freeze_support, set_start_method
|
from multiprocessing import freeze_support, set_start_method
|
||||||
|
|||||||
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')
|
||||||
123
kcc.iss
123
kcc.iss
@@ -1,123 +0,0 @@
|
|||||||
#define MyAppName "Kindle Comic Converter"
|
|
||||||
#define MyAppVersion "5.5.2"
|
|
||||||
#define MyAppPublisher "Ciro Mattia Gonano, Paweł Jastrzębski"
|
|
||||||
#define MyAppURL "http://kcc.iosphe.re/"
|
|
||||||
#define MyAppExeName "KCC.exe"
|
|
||||||
|
|
||||||
[Setup]
|
|
||||||
AppId={{7D279A59-C65E-4DA7-B165-56DD06596216}
|
|
||||||
AppName={#MyAppName}
|
|
||||||
AppVersion={#MyAppVersion}
|
|
||||||
AppPublisher={#MyAppPublisher}
|
|
||||||
AppPublisherURL={#MyAppURL}
|
|
||||||
AppSupportURL={#MyAppURL}
|
|
||||||
AppUpdatesURL={#MyAppURL}
|
|
||||||
AppCopyright=Copyright (C) 2012-2019 Ciro Mattia Gonano and Paweł Jastrzębski
|
|
||||||
ArchitecturesAllowed=x64
|
|
||||||
DefaultDirName={pf}\{#MyAppName}
|
|
||||||
DefaultGroupName={#MyAppName}
|
|
||||||
AllowNoIcons=yes
|
|
||||||
LicenseFile=LICENSE.txt
|
|
||||||
OutputBaseFilename=KindleComicConverter_win_{#MyAppVersion}
|
|
||||||
SetupIconFile=icons\comic2ebook.ico
|
|
||||||
SolidCompression=yes
|
|
||||||
ShowLanguageDialog=no
|
|
||||||
LanguageDetectionMethod=none
|
|
||||||
WizardImageFile=icons\Wizard.bmp
|
|
||||||
WizardSmallImageFile=icons\Wizard-Small.bmp
|
|
||||||
UninstallDisplayName={#MyAppName}
|
|
||||||
UninstallDisplayIcon={app}\{#MyAppExeName}
|
|
||||||
ChangesAssociations=True
|
|
||||||
InfoAfterFile=other\windows\InstallWarning.rtf
|
|
||||||
SignTool=SignTool /d $q{#MyAppName}$q /du $q{#MyAppURL}$q $f
|
|
||||||
MinVersion=0,6.0
|
|
||||||
OutputDir=dist
|
|
||||||
ArchitecturesInstallIn64BitMode=x64
|
|
||||||
|
|
||||||
[Languages]
|
|
||||||
Name: "english"; MessagesFile: "compiler:Default.isl"
|
|
||||||
|
|
||||||
[Tasks]
|
|
||||||
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
|
|
||||||
Name: "CBZassociation"; Description: "CBZ"; GroupDescription: "File associations:"
|
|
||||||
Name: "CBRassociation"; Description: "CBR"; GroupDescription: "File associations:"
|
|
||||||
Name: "CB7association"; Description: "CB7"; GroupDescription: "File associations:"
|
|
||||||
|
|
||||||
[Files]
|
|
||||||
Source: "dist\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion
|
|
||||||
Source: "LICENSE.txt"; DestDir: "{app}"; Flags: ignoreversion solidbreak
|
|
||||||
Source: "other\windows\Additional-LICENSE.txt"; DestDir: "{app}"; Flags: ignoreversion
|
|
||||||
Source: "other\windows\7z.exe"; DestDir: "{app}"; Flags: ignoreversion
|
|
||||||
Source: "other\windows\7z.dll"; DestDir: "{app}"; Flags: ignoreversion
|
|
||||||
|
|
||||||
[Icons]
|
|
||||||
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
|
|
||||||
Name: "{group}\Readme"; Filename: "https://github.com/ciromattia/kcc#kcc"
|
|
||||||
Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
|
|
||||||
|
|
||||||
[Run]
|
|
||||||
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall
|
|
||||||
|
|
||||||
[Messages]
|
|
||||||
WelcomeLabel1=Welcome to the KCC Setup Wizard
|
|
||||||
FinishedHeadingLabel=Completing the KCC Setup Wizard
|
|
||||||
|
|
||||||
[Registry]
|
|
||||||
Root: HKCR; SubKey: ".cbz"; ValueType: string; ValueData: "KCCZIP"; Flags: uninsdeletekey; Tasks: CBZassociation
|
|
||||||
Root: HKCR; SubKey: "KCCZIP"; ValueType: string; ValueData: "KCC ZIP Archive"; Flags: uninsdeletekey; Tasks: CBZassociation
|
|
||||||
Root: HKCR; SubKey: "KCCZIP\Shell\Open\Command"; ValueType: string; ValueData: """{app}\{#MyAppExeName}"" ""%1"""; Flags: uninsdeletekey; Tasks: CBZassociation
|
|
||||||
Root: HKCR; Subkey: "KCCZIP\DefaultIcon"; ValueType: string; ValueData: "{app}\{#MyAppExeName},0"; Flags: uninsdeletevalue; Tasks: CBZassociation
|
|
||||||
Root: HKCR; SubKey: ".cbr"; ValueType: string; ValueData: "KCCRAR"; Flags: uninsdeletekey; Tasks: CBRassociation
|
|
||||||
Root: HKCR; SubKey: "KCCRAR"; ValueType: string; ValueData: "KCC RAR Archive"; Flags: uninsdeletekey; Tasks: CBRassociation
|
|
||||||
Root: HKCR; SubKey: "KCCRAR\Shell\Open\Command"; ValueType: string; ValueData: """{app}\{#MyAppExeName}"" ""%1"""; Flags: uninsdeletekey; Tasks: CBRassociation
|
|
||||||
Root: HKCR; Subkey: "KCCRAR\DefaultIcon"; ValueType: string; ValueData: "{app}\{#MyAppExeName},0"; Flags: uninsdeletevalue; Tasks: CBRassociation
|
|
||||||
Root: HKCR; SubKey: ".cb7"; ValueType: string; ValueData: "KCCCB7"; Flags: uninsdeletekey; Tasks: CB7association
|
|
||||||
Root: HKCR; SubKey: "KCCCB7"; ValueType: string; ValueData: "KCC 7z Archive"; Flags: uninsdeletekey; Tasks: CB7association
|
|
||||||
Root: HKCR; SubKey: "KCCCB7\Shell\Open\Command"; ValueType: string; ValueData: """{app}\{#MyAppExeName}"" ""%1"""; Flags: uninsdeletekey; Tasks: CB7association
|
|
||||||
Root: HKCR; Subkey: "KCCCB7\DefaultIcon"; ValueType: string; ValueData: "{app}\{#MyAppExeName},0"; Flags: uninsdeletevalue; Tasks: CB7association
|
|
||||||
|
|
||||||
[Code]
|
|
||||||
function GetUninstallString(): String;
|
|
||||||
var
|
|
||||||
sUnInstPath: String;
|
|
||||||
sUnInstallString: String;
|
|
||||||
begin
|
|
||||||
sUnInstPath := ExpandConstant('Software\Microsoft\Windows\CurrentVersion\Uninstall\{#emit SetupSetting("AppId")}_is1');
|
|
||||||
sUnInstallString := '';
|
|
||||||
if not RegQueryStringValue(HKLM, sUnInstPath, 'UninstallString', sUnInstallString) then
|
|
||||||
RegQueryStringValue(HKCU, sUnInstPath, 'UninstallString', sUnInstallString);
|
|
||||||
Result := sUnInstallString;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function IsUpgrade(): Boolean;
|
|
||||||
begin
|
|
||||||
Result := (GetUninstallString() <> '');
|
|
||||||
end;
|
|
||||||
|
|
||||||
function UnInstallOldVersion(): Integer;
|
|
||||||
var
|
|
||||||
sUnInstallString: String;
|
|
||||||
iResultCode: Integer;
|
|
||||||
begin
|
|
||||||
Result := 0;
|
|
||||||
sUnInstallString := GetUninstallString();
|
|
||||||
if sUnInstallString <> '' then begin
|
|
||||||
sUnInstallString := RemoveQuotes(sUnInstallString);
|
|
||||||
if Exec(sUnInstallString, '/SILENT /NORESTART /SUPPRESSMSGBOXES','', SW_HIDE, ewWaitUntilTerminated, iResultCode) then
|
|
||||||
Result := 3
|
|
||||||
else
|
|
||||||
Result := 2;
|
|
||||||
end else
|
|
||||||
Result := 1;
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure CurStepChanged(CurStep: TSetupStep);
|
|
||||||
begin
|
|
||||||
if (CurStep=ssInstall) then
|
|
||||||
begin
|
|
||||||
if (IsUpgrade()) then
|
|
||||||
begin
|
|
||||||
UnInstallOldVersion();
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
41
kcc.py
41
kcc.py
@@ -19,25 +19,44 @@
|
|||||||
# PERFORMANCE OF THIS SOFTWARE.
|
# PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
if sys.version_info[0] != 3:
|
|
||||||
print('ERROR: This is Python 3 script!')
|
if sys.version_info < (3, 8, 0):
|
||||||
|
print('ERROR: This is a Python 3.8+ script!')
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
# OS specific workarounds
|
# OS specific workarounds
|
||||||
import os
|
import os
|
||||||
if sys.platform.startswith('darwin'):
|
if sys.platform.startswith('darwin'):
|
||||||
|
# prioritize KC2 since it optionally also installs KP3
|
||||||
|
mac_paths = [
|
||||||
|
'/Applications/Kindle Comic Creator/Kindle Comic Creator.app/Contents/MacOS',
|
||||||
|
'/Applications/Kindle Previewer 3.app/Contents/lib/fc/bin/',
|
||||||
|
]
|
||||||
if getattr(sys, 'frozen', False):
|
if getattr(sys, 'frozen', False):
|
||||||
os.environ['PATH'] = os.path.dirname(os.path.abspath(sys.executable)) + \
|
os.environ['PATH'] += os.pathsep + os.pathsep.join(mac_paths +
|
||||||
'/../Resources:/Applications/Kindle Comic Creator/Kindle Comic Creator.app/Contents/' \
|
[
|
||||||
'MacOS:/usr/local/bin:/usr/bin:/bin'
|
'/opt/homebrew/bin',
|
||||||
os.chdir(os.path.dirname(os.path.abspath(sys.executable)) + '/../Resources')
|
'/usr/local/bin',
|
||||||
else:
|
'/usr/bin',
|
||||||
os.chdir(os.path.dirname(os.path.abspath(__file__)))
|
'/bin',
|
||||||
elif sys.platform.startswith('win'):
|
]
|
||||||
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:
|
||||||
os.environ['PATH'] = os.path.dirname(os.path.abspath(__file__)) + '/other/windows/;' + os.environ['PATH']
|
os.environ['PATH'] += os.pathsep + os.pathsep.join(mac_paths)
|
||||||
|
os.chdir(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
elif sys.platform.startswith('win'):
|
||||||
|
# prioritize KC2 since it optionally also installs KP3
|
||||||
|
win_paths = [
|
||||||
|
os.path.expandvars('%LOCALAPPDATA%\\Amazon\\KC2'),
|
||||||
|
os.path.expandvars('%LOCALAPPDATA%\\Amazon\\Kindle Previewer 3\\lib\\fc\\bin\\'),
|
||||||
|
'C:\\Program Files\\7-Zip',
|
||||||
|
]
|
||||||
|
if getattr(sys, 'frozen', False):
|
||||||
|
os.environ['PATH'] += os.pathsep + os.pathsep.join(win_paths)
|
||||||
|
os.chdir(os.path.dirname(os.path.abspath(sys.executable)))
|
||||||
|
else:
|
||||||
|
os.environ['PATH'] += os.pathsep + os.pathsep.join(win_paths)
|
||||||
os.chdir(os.path.dirname(os.path.abspath(__file__)))
|
os.chdir(os.path.dirname(os.path.abspath(__file__)))
|
||||||
# Load additional Sentry configuration
|
# Load additional Sentry configuration
|
||||||
# if getattr(sys, 'frozen', False):
|
# 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')
|
||||||
@@ -16,11 +16,13 @@
|
|||||||
# OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
# OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||||
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
# PERFORMANCE OF THIS SOFTWARE.
|
# PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
import json
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
from urllib.parse import unquote
|
from urllib.parse import unquote
|
||||||
from urllib.request import urlretrieve
|
from urllib.request import urlretrieve, urlopen
|
||||||
from time import sleep
|
from time import sleep
|
||||||
from shutil import move, rmtree
|
from shutil import move, rmtree
|
||||||
from subprocess import STDOUT, PIPE
|
from subprocess import STDOUT, PIPE
|
||||||
@@ -112,12 +114,6 @@ class Icons:
|
|||||||
self.CBZFormat.addPixmap(QtGui.QPixmap(":/Formats/icons/CBZ.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
self.CBZFormat.addPixmap(QtGui.QPixmap(":/Formats/icons/CBZ.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||||
self.EPUBFormat = QtGui.QIcon()
|
self.EPUBFormat = QtGui.QIcon()
|
||||||
self.EPUBFormat.addPixmap(QtGui.QPixmap(":/Formats/icons/EPUB.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
self.EPUBFormat.addPixmap(QtGui.QPixmap(":/Formats/icons/EPUB.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||||
self.KFXFormat = QtGui.QIcon()
|
|
||||||
self.KFXFormat.addPixmap(QtGui.QPixmap(":/Formats/icons/KFX.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
|
||||||
self.MOBIEPUBFormat = QtGui.QIcon()
|
|
||||||
self.MOBIEPUBFormat.addPixmap(QtGui.QPixmap(":/Formats/icons/MOBI.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
|
||||||
self.EPUB200MBFormat = QtGui.QIcon()
|
|
||||||
self.EPUB200MBFormat.addPixmap(QtGui.QPixmap(":/Formats/icons/EPUB.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
|
||||||
|
|
||||||
self.info = QtGui.QIcon()
|
self.info = QtGui.QIcon()
|
||||||
self.info.addPixmap(QtGui.QPixmap(":/Status/icons/info.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
self.info.addPixmap(QtGui.QPixmap(":/Status/icons/info.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||||
@@ -142,64 +138,27 @@ class VersionThread(QtCore.QThread):
|
|||||||
self.wait()
|
self.wait()
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
# TODO adapt with github releases
|
try:
|
||||||
pass
|
last_version_url = urlopen("https://api.github.com/repos/ciromattia/kcc/releases/latest")
|
||||||
|
data = last_version_url.read()
|
||||||
|
encoding = last_version_url.info().get_content_charset('utf-8')
|
||||||
|
json_parser = json.loads(data.decode(encoding))
|
||||||
|
|
||||||
# try:
|
html_url = json_parser["html_url"]
|
||||||
# XML = parse(urlopen(Request('https://kcc.iosphe.re/Version/',
|
latest_version = json_parser["tag_name"]
|
||||||
# headers={'User-Agent': 'KindleComicConverter/' + __version__})))
|
latest_version = re.sub(r'^v', "", latest_version)
|
||||||
# except Exception:
|
|
||||||
# return
|
if ("b" not in __version__ and StrictVersion(latest_version) > StrictVersion(__version__)) \
|
||||||
# latestVersion = XML.childNodes[0].getElementsByTagName('LatestVersion')[0].childNodes[0].toxml()
|
or ("b" in __version__
|
||||||
# if ("beta" not in __version__ and StrictVersion(latestVersion) > StrictVersion(__version__)) \
|
and StrictVersion(latest_version) >= StrictVersion(re.sub(r'b.*', '', __version__))):
|
||||||
# or ("beta" in __version__
|
MW.addMessage.emit('<a href="' + html_url + '"><b>The new version is available!</b></a>', 'warning',
|
||||||
# and StrictVersion(latestVersion) >= StrictVersion(re.sub(r'-beta.*', '', __version__))):
|
False)
|
||||||
# if sys.platform.startswith('win'):
|
except Exception:
|
||||||
# self.newVersion = latestVersion
|
return
|
||||||
# self.md5 = XML.childNodes[0].getElementsByTagName('MD5')[0].childNodes[0].toxml()
|
|
||||||
# MW.showDialog.emit('<b>New version released!</b> <a href="https://github.com/ciromattia/kcc/releases/">'
|
|
||||||
# 'See changelog.</a><br/><br/>Installed version: ' + __version__ +
|
|
||||||
# '<br/>Current version: ' + latestVersion +
|
|
||||||
# '<br/><br/>Would you like to start automatic update?', 'question')
|
|
||||||
# self.getNewVersion()
|
|
||||||
# else:
|
|
||||||
# MW.addMessage.emit('<a href="https://kcc.iosphe.re/">'
|
|
||||||
# '<b>The new version is available!</b></a> '
|
|
||||||
# '(<a href="https://github.com/ciromattia/kcc/releases/">'
|
|
||||||
# 'Changelog</a>)', 'warning', False)
|
|
||||||
|
|
||||||
def setAnswer(self, dialoganswer):
|
def setAnswer(self, dialoganswer):
|
||||||
self.answer = dialoganswer
|
self.answer = dialoganswer
|
||||||
|
|
||||||
def getNewVersion(self):
|
|
||||||
while self.answer is None:
|
|
||||||
sleep(1)
|
|
||||||
if self.answer == QtWidgets.QMessageBox.Yes:
|
|
||||||
try:
|
|
||||||
MW.modeConvert.emit(-1)
|
|
||||||
MW.progressBarTick.emit('Downloading update')
|
|
||||||
path = urlretrieve('https://kcc.iosphe.re/Windows/KindleComicConverter_win_' +
|
|
||||||
self.newVersion + '.exe', reporthook=self.getNewVersionTick)
|
|
||||||
if self.md5 != md5Checksum(path[0]):
|
|
||||||
raise Exception
|
|
||||||
move(path[0], path[0] + '.exe')
|
|
||||||
MW.hideProgressBar.emit()
|
|
||||||
MW.modeConvert.emit(1)
|
|
||||||
Popen(path[0] + '.exe /SP- /silent /noicons', stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=True)
|
|
||||||
MW.forceShutdown.emit()
|
|
||||||
except Exception:
|
|
||||||
MW.addMessage.emit('Failed to download the update!', 'warning', False)
|
|
||||||
MW.hideProgressBar.emit()
|
|
||||||
MW.modeConvert.emit(1)
|
|
||||||
|
|
||||||
def getNewVersionTick(self, size, blocksize, totalsize):
|
|
||||||
progress = int((size / (totalsize // blocksize)) * 100)
|
|
||||||
if size == 0:
|
|
||||||
MW.progressBarTick.emit('100')
|
|
||||||
if progress > self.barProgress:
|
|
||||||
self.barProgress = progress
|
|
||||||
MW.progressBarTick.emit('tick')
|
|
||||||
|
|
||||||
|
|
||||||
class ProgressThread(QtCore.QThread):
|
class ProgressThread(QtCore.QThread):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@@ -255,12 +214,13 @@ class WorkerThread(QtCore.QThread):
|
|||||||
MW.modeConvert.emit(0)
|
MW.modeConvert.emit(0)
|
||||||
|
|
||||||
parser = comic2ebook.makeParser()
|
parser = comic2ebook.makeParser()
|
||||||
options, _ = parser.parse_args()
|
options = parser.parse_args()
|
||||||
argv = ''
|
argv = ''
|
||||||
currentJobs = []
|
currentJobs = []
|
||||||
|
|
||||||
options.profile = GUI.profiles[str(GUI.deviceBox.currentText())]['Label']
|
options.profile = GUI.profiles[str(GUI.deviceBox.currentText())]['Label']
|
||||||
options.format = str(GUI.formatBox.currentText()).replace('/AZW3', '')
|
gui_current_format = GUI.formats[str(GUI.formatBox.currentText())]['format']
|
||||||
|
options.format = gui_current_format
|
||||||
if GUI.mangaBox.isChecked():
|
if GUI.mangaBox.isChecked():
|
||||||
options.righttoleft = True
|
options.righttoleft = True
|
||||||
if GUI.rotateBox.checkState() == 1:
|
if GUI.rotateBox.checkState() == 1:
|
||||||
@@ -294,6 +254,8 @@ class WorkerThread(QtCore.QThread):
|
|||||||
options.maximizestrips = True
|
options.maximizestrips = True
|
||||||
if GUI.disableProcessingBox.isChecked():
|
if GUI.disableProcessingBox.isChecked():
|
||||||
options.noprocessing = True
|
options.noprocessing = True
|
||||||
|
if GUI.deleteBox.isChecked():
|
||||||
|
options.delete = True
|
||||||
if GUI.mozJpegBox.checkState() == 1:
|
if GUI.mozJpegBox.checkState() == 1:
|
||||||
options.forcepng = True
|
options.forcepng = True
|
||||||
elif GUI.mozJpegBox.checkState() == 2:
|
elif GUI.mozJpegBox.checkState() == 2:
|
||||||
@@ -314,7 +276,7 @@ class WorkerThread(QtCore.QThread):
|
|||||||
return
|
return
|
||||||
self.errors = False
|
self.errors = False
|
||||||
MW.addMessage.emit('<b>Source:</b> ' + job, 'info', False)
|
MW.addMessage.emit('<b>Source:</b> ' + job, 'info', False)
|
||||||
if str(GUI.formatBox.currentText()) == 'CBZ':
|
if gui_current_format == 'CBZ':
|
||||||
MW.addMessage.emit('Creating CBZ files', 'info', False)
|
MW.addMessage.emit('Creating CBZ files', 'info', False)
|
||||||
GUI.progress.content = 'Creating CBZ files'
|
GUI.progress.content = 'Creating CBZ files'
|
||||||
else:
|
else:
|
||||||
@@ -364,11 +326,11 @@ class WorkerThread(QtCore.QThread):
|
|||||||
return
|
return
|
||||||
if not self.errors:
|
if not self.errors:
|
||||||
GUI.progress.content = ''
|
GUI.progress.content = ''
|
||||||
if str(GUI.formatBox.currentText()) == 'CBZ':
|
if gui_current_format == 'CBZ':
|
||||||
MW.addMessage.emit('Creating CBZ files... <b>Done!</b>', 'info', True)
|
MW.addMessage.emit('Creating CBZ files... <b>Done!</b>', 'info', True)
|
||||||
else:
|
else:
|
||||||
MW.addMessage.emit('Creating EPUB files... <b>Done!</b>', 'info', True)
|
MW.addMessage.emit('Creating EPUB files... <b>Done!</b>', 'info', True)
|
||||||
if str(GUI.formatBox.currentText()) == 'MOBI/AZW3' or str(GUI.formatBox.currentText()) == 'MOBI+EPUB':
|
if 'MOBI' in gui_current_format:
|
||||||
MW.progressBarTick.emit('Creating MOBI files')
|
MW.progressBarTick.emit('Creating MOBI files')
|
||||||
MW.progressBarTick.emit(str(len(outputPath) * 2 + 1))
|
MW.progressBarTick.emit(str(len(outputPath) * 2 + 1))
|
||||||
MW.progressBarTick.emit('tick')
|
MW.progressBarTick.emit('tick')
|
||||||
@@ -504,7 +466,8 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
fnames = QtWidgets.QFileDialog.getOpenFileNames(MW, 'Select file', self.lastPath,
|
fnames = QtWidgets.QFileDialog.getOpenFileNames(MW, 'Select file', self.lastPath,
|
||||||
'Comic (*.cbz *.cbr *.cb7 *.zip *.rar *.7z *.pdf);;All (*.*)')
|
'Comic (*.cbz *.cbr *.cb7 *.zip *.rar *.7z *.pdf);;All (*.*)')
|
||||||
else:
|
else:
|
||||||
fnames = QtWidgets.QFileDialog.getOpenFileNames(MW, 'Select file', self.lastPath, 'Comic (*.pdf);;All (*.*)')
|
fnames = QtWidgets.QFileDialog.getOpenFileNames(MW, 'Select file', self.lastPath,
|
||||||
|
'Comic (*.pdf);;All (*.*)')
|
||||||
for fname in fnames[0]:
|
for fname in fnames[0]:
|
||||||
if fname != '':
|
if fname != '':
|
||||||
if sys.platform.startswith('win'):
|
if sys.platform.startswith('win'):
|
||||||
@@ -615,7 +578,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
|
|
||||||
def togglecroppingBox(self, value):
|
def togglecroppingBox(self, value):
|
||||||
if value:
|
if value:
|
||||||
GUI.croppingWidget.setVisible(True)
|
GUI.croppingWidget.setVisible(True)
|
||||||
else:
|
else:
|
||||||
GUI.croppingWidget.setVisible(False)
|
GUI.croppingWidget.setVisible(False)
|
||||||
self.changeCroppingPower(100) # 1.0
|
self.changeCroppingPower(100) # 1.0
|
||||||
@@ -681,6 +644,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
if not GUI.webtoonBox.isChecked():
|
if not GUI.webtoonBox.isChecked():
|
||||||
GUI.qualityBox.setEnabled(profile['PVOptions'])
|
GUI.qualityBox.setEnabled(profile['PVOptions'])
|
||||||
GUI.upscaleBox.setChecked(profile['DefaultUpscale'])
|
GUI.upscaleBox.setChecked(profile['DefaultUpscale'])
|
||||||
|
GUI.mangaBox.setChecked(True)
|
||||||
if not profile['PVOptions']:
|
if not profile['PVOptions']:
|
||||||
GUI.qualityBox.setChecked(False)
|
GUI.qualityBox.setChecked(False)
|
||||||
if str(GUI.deviceBox.currentText()) == 'Other':
|
if str(GUI.deviceBox.currentText()) == 'Other':
|
||||||
@@ -695,7 +659,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
GUI.formatBox.setCurrentIndex(profile['DefaultFormat'])
|
GUI.formatBox.setCurrentIndex(profile['DefaultFormat'])
|
||||||
if not GUI.webtoonBox.isChecked():
|
if not GUI.webtoonBox.isChecked():
|
||||||
GUI.qualityBox.setEnabled(profile['PVOptions'])
|
GUI.qualityBox.setEnabled(profile['PVOptions'])
|
||||||
if str(GUI.formatBox.currentText()) == 'MOBI/AZW3':
|
if GUI.formats[str(GUI.formatBox.currentText())]['format'] == 'MOBI':
|
||||||
GUI.outputSplit.setEnabled(True)
|
GUI.outputSplit.setEnabled(True)
|
||||||
else:
|
else:
|
||||||
GUI.outputSplit.setEnabled(False)
|
GUI.outputSplit.setEnabled(False)
|
||||||
@@ -729,8 +693,8 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
QtWidgets.QMessageBox.critical(MW, 'KCC - Error', message, QtWidgets.QMessageBox.Ok)
|
QtWidgets.QMessageBox.critical(MW, 'KCC - Error', message, QtWidgets.QMessageBox.Ok)
|
||||||
elif kind == 'question':
|
elif kind == 'question':
|
||||||
GUI.versionCheck.setAnswer(QtWidgets.QMessageBox.question(MW, 'KCC - Question', message,
|
GUI.versionCheck.setAnswer(QtWidgets.QMessageBox.question(MW, 'KCC - Question', message,
|
||||||
QtWidgets.QMessageBox.Yes,
|
QtWidgets.QMessageBox.Yes,
|
||||||
QtWidgets.QMessageBox.No))
|
QtWidgets.QMessageBox.No))
|
||||||
|
|
||||||
def updateProgressbar(self, command):
|
def updateProgressbar(self, command):
|
||||||
if command == 'tick':
|
if command == 'tick':
|
||||||
@@ -777,22 +741,21 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
self.addMessage('Target resolution is not set!', 'error')
|
self.addMessage('Target resolution is not set!', 'error')
|
||||||
self.needClean = True
|
self.needClean = True
|
||||||
return
|
return
|
||||||
if str(GUI.formatBox.currentText()) == 'MOBI/AZW3' and not self.kindleGen:
|
if 'MOBI' in GUI.formats[str(GUI.formatBox.currentText())]['format'] and not self.kindleGen:
|
||||||
self.detectKindleGen()
|
self.detectKindleGen()
|
||||||
if not self.kindleGen:
|
if not self.kindleGen:
|
||||||
GUI.jobList.clear()
|
GUI.jobList.clear()
|
||||||
self.addMessage('Cannot find <a href="http://www.amazon.com/gp/feature.html?ie=UTF8&docId='
|
self.display_kindlegen_missing()
|
||||||
'1000765211"><b>KindleGen</b></a>! MOBI conversion is unavailable!', 'error')
|
|
||||||
if sys.platform.startswith('win'):
|
|
||||||
self.addMessage('Download it and place EXE in KCC directory.', 'error')
|
|
||||||
elif sys.platform.startswith('darwin'):
|
|
||||||
self.addMessage('Install it using <a href="http://brew.sh/">Brew</a>.', 'error')
|
|
||||||
else:
|
|
||||||
self.addMessage('Download it and place executable in /usr/local/bin directory.', 'error')
|
|
||||||
self.needClean = True
|
self.needClean = True
|
||||||
return
|
return
|
||||||
self.worker.start()
|
self.worker.start()
|
||||||
|
|
||||||
|
def display_kindlegen_missing(self):
|
||||||
|
self.addMessage(
|
||||||
|
'<a href="https://github.com/ciromattia/kcc/wiki/Installation#kindlegen"><b>Cannot find KindleGen</b></a>: MOBI conversion is unavailable!',
|
||||||
|
'error'
|
||||||
|
)
|
||||||
|
|
||||||
def saveSettings(self, event):
|
def saveSettings(self, event):
|
||||||
if self.conversionAlive:
|
if self.conversionAlive:
|
||||||
GUI.convertButton.setEnabled(False)
|
GUI.convertButton.setEnabled(False)
|
||||||
@@ -823,6 +786,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
'mozJpegBox': GUI.mozJpegBox.checkState(),
|
'mozJpegBox': GUI.mozJpegBox.checkState(),
|
||||||
'widthBox': GUI.widthBox.value(),
|
'widthBox': GUI.widthBox.value(),
|
||||||
'heightBox': GUI.heightBox.value(),
|
'heightBox': GUI.heightBox.value(),
|
||||||
|
'deleteBox': GUI.deleteBox.checkState(),
|
||||||
'maximizeStrips': GUI.maximizeStrips.checkState(),
|
'maximizeStrips': GUI.maximizeStrips.checkState(),
|
||||||
'gammaSlider': float(self.gammaValue) * 100})
|
'gammaSlider': float(self.gammaValue) * 100})
|
||||||
self.settings.sync()
|
self.settings.sync()
|
||||||
@@ -885,21 +849,21 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
if 'Amazon kindlegen' in line:
|
if 'Amazon kindlegen' in line:
|
||||||
versionCheck = line.split('V')[1].split(' ')[0]
|
versionCheck = line.split('V')[1].split(' ')[0]
|
||||||
if StrictVersion(versionCheck) < StrictVersion('2.9'):
|
if StrictVersion(versionCheck) < StrictVersion('2.9'):
|
||||||
self.addMessage('Your <a href="http://www.amazon.com/gp/feature.html?ie=UTF8&docId='
|
self.addMessage('Your <a href="https://www.amazon.com/b?node=23496309011">KindleGen</a>'
|
||||||
'1000765211">KindleGen</a> is outdated! MOBI conversion might fail.', 'warning')
|
' is outdated! MOBI conversion might fail.', 'warning')
|
||||||
break
|
break
|
||||||
|
where_command = 'where kindlegen.exe'
|
||||||
|
if os.name == 'posix':
|
||||||
|
where_command = 'which kindlegen'
|
||||||
|
process = subprocess.run(where_command, stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=True)
|
||||||
|
locations = process.stdout.decode('utf-8').split('\n')
|
||||||
|
self.addMessage(f"<b>KindleGen Found:</b> {locations[0]}", 'info')
|
||||||
else:
|
else:
|
||||||
self.kindleGen = False
|
self.kindleGen = False
|
||||||
if startup:
|
if startup:
|
||||||
self.addMessage('Cannot find <a href="http://www.amazon.com/gp/feature.html?ie=UTF8&docId=1000765211">'
|
self.display_kindlegen_missing()
|
||||||
'<b>KindleGen</b></a>! MOBI conversion will be unavailable!', 'error')
|
|
||||||
if sys.platform.startswith('win'):
|
|
||||||
self.addMessage('Download it and place EXE in KCC directory.', 'error')
|
|
||||||
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')
|
|
||||||
else:
|
|
||||||
self.addMessage('Download it and place executable in /usr/local/bin directory.', 'error')
|
|
||||||
|
|
||||||
def __init__(self, kccapp, kccwindow):
|
def __init__(self, kccapp, kccwindow):
|
||||||
global APP, MW, GUI
|
global APP, MW, GUI
|
||||||
@@ -949,6 +913,16 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
if self.windowSize == '0x0':
|
if self.windowSize == '0x0':
|
||||||
MW.resize(500, 500)
|
MW.resize(500, 500)
|
||||||
|
|
||||||
|
self.formats = { # text, icon, data/option_format
|
||||||
|
"MOBI/AZW3": {'icon': 'MOBI', 'format': 'MOBI'},
|
||||||
|
"EPUB": {'icon': 'EPUB', 'format': 'EPUB'},
|
||||||
|
"CBZ": {'icon': 'CBZ', 'format': 'CBZ'},
|
||||||
|
"EPUB (Calibre KFX)": {'icon': 'EPUB', 'format': 'KFX'},
|
||||||
|
"MOBI + EPUB": {'icon': 'MOBI', 'format': 'MOBI+EPUB'},
|
||||||
|
"EPUB (200MB limit)": {'icon': 'EPUB', 'format': 'EPUB-200MB'}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
self.profiles = {
|
self.profiles = {
|
||||||
"Kindle Oasis 2/3": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
"Kindle Oasis 2/3": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
||||||
'DefaultUpscale': True, 'Label': 'KO'},
|
'DefaultUpscale': True, 'Label': 'KO'},
|
||||||
@@ -957,7 +931,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
"Kindle Voyage": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
"Kindle Voyage": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
||||||
'DefaultUpscale': True, 'Label': 'KV'},
|
'DefaultUpscale': True, 'Label': 'KV'},
|
||||||
"Kindle Scribe": {
|
"Kindle Scribe": {
|
||||||
'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0, 'DefaultUpscale': True, 'Label': 'KS',
|
'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0, 'DefaultUpscale': False, 'Label': 'KS',
|
||||||
},
|
},
|
||||||
"Kindle 11": {
|
"Kindle 11": {
|
||||||
'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0, 'DefaultUpscale': True, 'Label': 'K11',
|
'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0, 'DefaultUpscale': True, 'Label': 'K11',
|
||||||
@@ -1071,8 +1045,8 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
self.sevenzip = True
|
self.sevenzip = True
|
||||||
else:
|
else:
|
||||||
self.sevenzip = False
|
self.sevenzip = False
|
||||||
self.addMessage('Cannot find <a href="http://www.7-zip.org/download.html">7z</a>!'
|
self.addMessage('<a href="https://github.com/ciromattia/kcc/wiki/Installation#7-zip">Cannot find 7z</a>!'
|
||||||
' Processing of archives will be disabled.', 'warning')
|
' CBZ/CBR/ZIP/etc processing disabled.', 'warning')
|
||||||
self.detectKindleGen(True)
|
self.detectKindleGen(True)
|
||||||
|
|
||||||
APP.messageFromOtherInstance.connect(self.handleMessage)
|
APP.messageFromOtherInstance.connect(self.handleMessage)
|
||||||
@@ -1113,9 +1087,8 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
GUI.deviceBox.addItem(self.icons.deviceKobo, profile)
|
GUI.deviceBox.addItem(self.icons.deviceKobo, profile)
|
||||||
else:
|
else:
|
||||||
GUI.deviceBox.addItem(self.icons.deviceKindle, profile)
|
GUI.deviceBox.addItem(self.icons.deviceKindle, profile)
|
||||||
for f in ['MOBI/AZW3', 'EPUB', 'CBZ', 'KFX', 'MOBI+EPUB', 'EPUB-200MB']:
|
for f in self.formats:
|
||||||
format_prefix = f.replace('/AZW3', '').replace('+', '').replace('-', '')
|
GUI.formatBox.addItem(eval('self.icons.' + self.formats[f]['icon'] + 'Format'), f)
|
||||||
GUI.formatBox.addItem(eval('self.icons.' + format_prefix + 'Format'), f)
|
|
||||||
if self.lastDevice > GUI.deviceBox.count():
|
if self.lastDevice > GUI.deviceBox.count():
|
||||||
self.lastDevice = 0
|
self.lastDevice = 0
|
||||||
if profilesGUI[self.lastDevice] == "Separator":
|
if profilesGUI[self.lastDevice] == "Separator":
|
||||||
@@ -1149,7 +1122,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
self.versionCheck.start()
|
self.versionCheck.start()
|
||||||
self.tray.show()
|
self.tray.show()
|
||||||
|
|
||||||
# Cleanup unfisnished conversion
|
# Cleanup unfinished conversion
|
||||||
for root, dirs, _ in walkLevel(gettempdir(), 0):
|
for root, dirs, _ in walkLevel(gettempdir(), 0):
|
||||||
for tempdir in dirs:
|
for tempdir in dirs:
|
||||||
if tempdir.startswith('KCC-'):
|
if tempdir.startswith('KCC-'):
|
||||||
|
|||||||
@@ -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.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
|
# 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.
|
# 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.setTristate(True)
|
||||||
self.croppingBox.setObjectName("croppingBox")
|
self.croppingBox.setObjectName("croppingBox")
|
||||||
self.gridLayout_2.addWidget(self.croppingBox, 3, 2, 1, 1)
|
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 = QtWidgets.QCheckBox(self.optionWidget)
|
||||||
self.disableProcessingBox.setObjectName("disableProcessingBox")
|
self.disableProcessingBox.setObjectName("disableProcessingBox")
|
||||||
self.gridLayout_2.addWidget(self.disableProcessingBox, 4, 2, 1, 1)
|
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.colorBox, self.croppingBox)
|
||||||
mainWindow.setTabOrder(self.croppingBox, self.mozJpegBox)
|
mainWindow.setTabOrder(self.croppingBox, self.mozJpegBox)
|
||||||
mainWindow.setTabOrder(self.mozJpegBox, self.maximizeStrips)
|
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.disableProcessingBox, self.editorButton)
|
||||||
mainWindow.setTabOrder(self.editorButton, self.wikiButton)
|
mainWindow.setTabOrder(self.editorButton, self.wikiButton)
|
||||||
mainWindow.setTabOrder(self.wikiButton, self.jobList)
|
mainWindow.setTabOrder(self.wikiButton, self.jobList)
|
||||||
@@ -290,7 +294,9 @@ class Ui_mainWindow(object):
|
|||||||
self.maximizeStrips.setText(_translate("mainWindow", "1x4 to 2x2 strips"))
|
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.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.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.disableProcessingBox.setText(_translate("mainWindow", "Disable processing"))
|
||||||
self.gammaLabel.setText(_translate("mainWindow", "Gamma: Auto"))
|
self.gammaLabel.setText(_translate("mainWindow", "Gamma: Auto"))
|
||||||
self.croppingPowerLabel.setText(_translate("mainWindow", "Cropping power:"))
|
self.croppingPowerLabel.setText(_translate("mainWindow", "Cropping power:"))
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
__version__ = '5.6.0'
|
__version__ = '5.6.3'
|
||||||
__license__ = 'ISC'
|
__license__ = 'ISC'
|
||||||
__copyright__ = '2012-2022, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>, darodi'
|
__copyright__ = '2012-2022, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>, darodi'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
from argparse import ArgumentParser
|
||||||
from time import strftime, gmtime
|
from time import strftime, gmtime
|
||||||
from copy import copy
|
from copy import copy
|
||||||
from glob import glob, escape
|
from glob import glob, escape
|
||||||
@@ -27,11 +28,10 @@ from re import sub
|
|||||||
from stat import S_IWRITE, S_IREAD, S_IEXEC
|
from stat import S_IWRITE, S_IREAD, S_IEXEC
|
||||||
from zipfile import ZipFile, ZIP_STORED, ZIP_DEFLATED
|
from zipfile import ZipFile, ZIP_STORED, ZIP_DEFLATED
|
||||||
from tempfile import mkdtemp, gettempdir, TemporaryFile
|
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 multiprocessing import Pool
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
from slugify import slugify as slugifyExt
|
from slugify import slugify as slugify_ext
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
from subprocess import STDOUT, PIPE
|
from subprocess import STDOUT, PIPE
|
||||||
from psutil import Popen, virtual_memory, disk_usage
|
from psutil import Popen, virtual_memory, disk_usage
|
||||||
@@ -54,23 +54,23 @@ from . import __version__
|
|||||||
def main(argv=None):
|
def main(argv=None):
|
||||||
global options
|
global options
|
||||||
parser = makeParser()
|
parser = makeParser()
|
||||||
optionstemplate, args = parser.parse_args(argv)
|
args = parser.parse_args(argv)
|
||||||
if len(args) == 0:
|
options = copy(args)
|
||||||
|
if not argv or options.input == []:
|
||||||
parser.print_help()
|
parser.print_help()
|
||||||
return 0
|
return 0
|
||||||
if sys.platform.startswith('win'):
|
if sys.platform.startswith('win'):
|
||||||
sources = set([source for arg in args for source in glob(escape(arg))])
|
sources = set([source for option in options.input for source in glob(escape(option))])
|
||||||
else:
|
else:
|
||||||
sources = set(args)
|
sources = set(options.input)
|
||||||
if len(sources) == 0:
|
if len(sources) == 0:
|
||||||
print('No matching files found.')
|
print('No matching files found.')
|
||||||
return 1
|
return 1
|
||||||
for source in sources:
|
for source in sources:
|
||||||
source = source.rstrip('\\').rstrip('/')
|
source = source.rstrip('\\').rstrip('/')
|
||||||
options = copy(optionstemplate)
|
options = copy(args)
|
||||||
options = checkOptions(options)
|
options = checkOptions(options)
|
||||||
if len(sources) > 1:
|
print('Working on ' + source + '...')
|
||||||
print('Working on ' + source + '...')
|
|
||||||
makeBook(source)
|
makeBook(source)
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
@@ -295,13 +295,19 @@ def buildOPF(dstdir, title, filelist, cover=None):
|
|||||||
"<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",
|
||||||
|
"<meta property=\"rendition:spread\">landscape</meta>\n",
|
||||||
|
"<meta property=\"rendition:layout\">pre-paginated</meta>\n",
|
||||||
|
"<meta name=\"orientation-lock\" content=\"none\"/>\n"])
|
||||||
if options.kfx:
|
if options.kfx:
|
||||||
f.writelines(["<meta name=\"orientation-lock\" content=\"none\"/>\n",
|
f.writelines(["<meta name=\"region-mag\" content=\"false\"/>\n"])
|
||||||
"<meta name=\"region-mag\" content=\"false\"/>\n"])
|
|
||||||
else:
|
else:
|
||||||
f.writelines(["<meta name=\"orientation-lock\" content=\"portrait\"/>\n",
|
f.writelines(["<meta name=\"region-mag\" content=\"true\"/>\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:
|
else:
|
||||||
f.writelines(["<meta property=\"rendition:orientation\">portrait</meta>\n",
|
f.writelines(["<meta property=\"rendition:orientation\">portrait</meta>\n",
|
||||||
"<meta property=\"rendition:spread\">portrait</meta>\n",
|
"<meta property=\"rendition:spread\">portrait</meta>\n",
|
||||||
@@ -334,38 +340,64 @@ def buildOPF(dstdir, title, filelist, cover=None):
|
|||||||
f.write("<item id=\"img_" + str(uniqueid) + "\" href=\"" + folder + "/" + path[1] + "\" media-type=\"" +
|
f.write("<item id=\"img_" + str(uniqueid) + "\" href=\"" + folder + "/" + path[1] + "\" media-type=\"" +
|
||||||
mt + "\"/>\n")
|
mt + "\"/>\n")
|
||||||
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")
|
||||||
|
|
||||||
|
|
||||||
|
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:
|
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"
|
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")
|
||||||
pageside = "left"
|
pageside = "left"
|
||||||
if options.iskindle:
|
if options.iskindle or options.supportSyntheticSpread:
|
||||||
for entry in reflist:
|
for entry in reflist:
|
||||||
if options.righttoleft:
|
if options.righttoleft:
|
||||||
if entry.endswith("-b"):
|
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"
|
pageside = "right"
|
||||||
elif entry.endswith("-c"):
|
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"
|
pageside = "right"
|
||||||
else:
|
else:
|
||||||
f.write("<itemref idref=\"page_" + entry + "\" linear=\"yes\" properties=\"page-spread-" +
|
f.write(
|
||||||
pageside + "\"/>\n")
|
"<itemref idref=\"page_%s\" %s/>\n" % (entry,
|
||||||
|
pageSpreadProperty(pageside))
|
||||||
|
)
|
||||||
if pageside == "right":
|
if pageside == "right":
|
||||||
pageside = "left"
|
pageside = "left"
|
||||||
else:
|
else:
|
||||||
pageside = "right"
|
pageside = "right"
|
||||||
else:
|
else:
|
||||||
if entry.endswith("-b"):
|
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"
|
pageside = "left"
|
||||||
elif entry.endswith("-c"):
|
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"
|
pageside = "left"
|
||||||
else:
|
else:
|
||||||
f.write("<itemref idref=\"page_" + entry + "\" linear=\"yes\" properties=\"page-spread-" +
|
f.write(
|
||||||
pageside + "\"/>\n")
|
"<itemref idref=\"page_%s\" %s/>\n" % (entry,
|
||||||
|
pageSpreadProperty(pageside))
|
||||||
|
)
|
||||||
if pageside == "right":
|
if pageside == "right":
|
||||||
pageside = "left"
|
pageside = "left"
|
||||||
else:
|
else:
|
||||||
@@ -482,18 +514,30 @@ def buildEPUB(path, chapternames, tomenumber):
|
|||||||
# 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
|
|
||||||
|
global_diff = 0
|
||||||
|
diff_delta = 0
|
||||||
|
|
||||||
|
# if split
|
||||||
|
if options.splitter == 0:
|
||||||
|
diff_delta = 1
|
||||||
|
# if rotate and split
|
||||||
|
elif options.splitter == 2:
|
||||||
|
diff_delta = 2
|
||||||
|
|
||||||
for aChapter in options.chapters:
|
for aChapter in options.chapters:
|
||||||
pageid = aChapter[0]
|
pageid = aChapter[0]
|
||||||
for x in range(0, pageid + globaldiff + 1):
|
cur_diff = global_diff
|
||||||
|
global_diff = 0
|
||||||
|
|
||||||
|
for x in range(0, pageid + cur_diff + 1):
|
||||||
if '-kcc-b' in filelist[x][1]:
|
if '-kcc-b' in filelist[x][1]:
|
||||||
pageid += 1
|
pageid += diff_delta
|
||||||
if '-kcc-c' in filelist[pageid][1]:
|
global_diff += diff_delta
|
||||||
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)
|
|
||||||
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)
|
||||||
@@ -515,7 +559,7 @@ def imgDirectoryProcessing(path):
|
|||||||
GUI.progressBarTick.emit(str(pagenumber))
|
GUI.progressBarTick.emit(str(pagenumber))
|
||||||
if len(work) > 0:
|
if len(work) > 0:
|
||||||
for i in work:
|
for i in work:
|
||||||
workerPool.apply_async(func=imgFileProcessing, args=(i, ), callback=imgFileProcessingTick)
|
workerPool.apply_async(func=imgFileProcessing, args=(i,), callback=imgFileProcessingTick)
|
||||||
workerPool.close()
|
workerPool.close()
|
||||||
workerPool.join()
|
workerPool.join()
|
||||||
if GUI and not GUI.conversionAlive:
|
if GUI and not GUI.conversionAlive:
|
||||||
@@ -557,9 +601,9 @@ def imgFileProcessing(work):
|
|||||||
for i in workImg.payload:
|
for i in workImg.payload:
|
||||||
img = image.ComicPage(opt, *i)
|
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, opt.croppingm)
|
||||||
if opt.cropping > 0 and not opt.webtoon:
|
if opt.cropping > 0 and not opt.webtoon:
|
||||||
img.cropMargin(opt.croppingp)
|
img.cropMargin(opt.croppingp, opt.croppingm)
|
||||||
img.autocontrastImage()
|
img.autocontrastImage()
|
||||||
img.resizeImage()
|
img.resizeImage()
|
||||||
if opt.forcepng and not opt.forcecolor:
|
if opt.forcepng and not opt.forcecolor:
|
||||||
@@ -600,7 +644,7 @@ def getWorkFolder(afile):
|
|||||||
path = cbx.extract(workdir)
|
path = cbx.extract(workdir)
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
rmtree(workdir, True)
|
rmtree(workdir, True)
|
||||||
raise UserWarning(e.strerror)
|
raise UserWarning(e)
|
||||||
else:
|
else:
|
||||||
raise UserWarning("Failed to open source file/directory.")
|
raise UserWarning("Failed to open source file/directory.")
|
||||||
sanitizePermissions(path)
|
sanitizePermissions(path)
|
||||||
@@ -664,7 +708,9 @@ def getComicInfo(path, originalpath):
|
|||||||
os.remove(xmlPath)
|
os.remove(xmlPath)
|
||||||
return
|
return
|
||||||
options.authors = []
|
options.authors = []
|
||||||
if defaultTitle:
|
if xml.data['Title']:
|
||||||
|
options.title = hescape(xml.data['Title'])
|
||||||
|
elif defaultTitle:
|
||||||
if xml.data['Series']:
|
if xml.data['Series']:
|
||||||
options.title = hescape(xml.data['Series'])
|
options.title = hescape(xml.data['Series'])
|
||||||
if xml.data['Volume']:
|
if xml.data['Volume']:
|
||||||
@@ -715,19 +761,23 @@ def getPanelViewSize(deviceres, size):
|
|||||||
def sanitizeTree(filetree):
|
def sanitizeTree(filetree):
|
||||||
chapterNames = {}
|
chapterNames = {}
|
||||||
for root, dirs, files in os.walk(filetree, False):
|
for root, dirs, files in os.walk(filetree, False):
|
||||||
for name in files:
|
for i, name in enumerate(sorted(files)):
|
||||||
splitname = os.path.splitext(name)
|
splitname = os.path.splitext(name)
|
||||||
slugified = slugify(splitname[0], False)
|
|
||||||
while os.path.exists(os.path.join(root, slugified + splitname[1])) and splitname[0].upper()\
|
# file needs kcc at front AND back to avoid renaming issues
|
||||||
!= slugified.upper():
|
slugified = f'kcc-{i:04}'
|
||||||
slugified += "A"
|
for suffix in '-KCC', '-KCC-A', '-KCC-B', '-KCC-C':
|
||||||
|
if splitname[0].endswith(suffix):
|
||||||
|
slugified += suffix.lower()
|
||||||
|
break
|
||||||
|
|
||||||
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:
|
||||||
os.replace(key, newKey)
|
os.replace(key, newKey)
|
||||||
for name in dirs:
|
for name in dirs:
|
||||||
tmpName = name
|
tmpName = name
|
||||||
slugified = slugify(name, True)
|
slugified = slugify(name)
|
||||||
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
|
||||||
@@ -738,23 +788,6 @@ def sanitizeTree(filetree):
|
|||||||
return chapterNames
|
return chapterNames
|
||||||
|
|
||||||
|
|
||||||
def sanitizeTreeKobo(filetree):
|
|
||||||
pageNumber = 0
|
|
||||||
for root, dirs, files in os.walk(filetree):
|
|
||||||
dirs, files = walkSort(dirs, files)
|
|
||||||
for name in files:
|
|
||||||
splitname = os.path.splitext(name)
|
|
||||||
slugified = str(pageNumber).zfill(5)
|
|
||||||
pageNumber += 1
|
|
||||||
while os.path.exists(os.path.join(root, slugified + splitname[1])) and splitname[0].upper()\
|
|
||||||
!= slugified.upper():
|
|
||||||
slugified += "A"
|
|
||||||
newKey = os.path.join(root, slugified + splitname[1])
|
|
||||||
key = os.path.join(root, name)
|
|
||||||
if key != newKey:
|
|
||||||
os.replace(key, newKey)
|
|
||||||
|
|
||||||
|
|
||||||
def sanitizePermissions(filetree):
|
def sanitizePermissions(filetree):
|
||||||
for root, dirs, files in os.walk(filetree, False):
|
for root, dirs, files in os.walk(filetree, False):
|
||||||
for name in files:
|
for name in files:
|
||||||
@@ -877,11 +910,8 @@ def createNewTome():
|
|||||||
return tomePath, tomePathRoot
|
return tomePath, tomePathRoot
|
||||||
|
|
||||||
|
|
||||||
def slugify(value, isdir):
|
def slugify(value):
|
||||||
if isdir:
|
value = slugify_ext(value, regex_pattern=r'[^-a-z0-9_\.]+').strip('.')
|
||||||
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
|
||||||
|
|
||||||
@@ -902,90 +932,95 @@ def makeZIP(zipfilename, basedir, isepub=False):
|
|||||||
|
|
||||||
|
|
||||||
def makeParser():
|
def makeParser():
|
||||||
psr = OptionParser(usage="Usage: kcc-c2e [options] comic_file|comic_folder", add_help_option=False)
|
psr = ArgumentParser(prog="kcc-c2e", usage="kcc-c2e [options] [input]", add_help=False)
|
||||||
|
|
||||||
mainOptions = OptionGroup(psr, "MAIN")
|
mandatory_options = psr.add_argument_group("MANDATORY")
|
||||||
processingOptions = OptionGroup(psr, "PROCESSING")
|
main_options = psr.add_argument_group("MAIN")
|
||||||
outputOptions = OptionGroup(psr, "OUTPUT SETTINGS")
|
processing_options = psr.add_argument_group("PROCESSING")
|
||||||
customProfileOptions = OptionGroup(psr, "CUSTOM PROFILE")
|
output_options = psr.add_argument_group("OUTPUT SETTINGS")
|
||||||
otherOptions = OptionGroup(psr, "OTHER")
|
custom_profile_options = psr.add_argument_group("CUSTOM PROFILE")
|
||||||
|
other_options = psr.add_argument_group("OTHER")
|
||||||
|
|
||||||
mainOptions.add_option("-p", "--profile", action="store", dest="profile", default="KV",
|
mandatory_options.add_argument("input", action="extend", nargs="*", default=None,
|
||||||
help="Device profile (Available options: K1, K2, K34, K578, KDX, KPW, KPW5, KV, KO, "
|
help="Full path to comic folder or file(s) to be processed.")
|
||||||
"K11, KS, KoMT, KoG, KoGHD, KoA, KoAHD, KoAH2O, KoAO, KoN, KoC, KoL, KoF, KoS, KoE)"
|
|
||||||
" [Default=KV]")
|
|
||||||
mainOptions.add_option("-m", "--manga-style", action="store_true", dest="righttoleft", default=False,
|
|
||||||
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,
|
|
||||||
help="Display two not four panels in Panel View mode")
|
|
||||||
mainOptions.add_option("-w", "--webtoon", action="store_true", dest="webtoon", default=False,
|
|
||||||
help="Webtoon processing mode"),
|
|
||||||
mainOptions.add_option("--targetsize", type="int", dest="targetsize", default=None,
|
|
||||||
help="the maximal size of output file in MB."
|
|
||||||
" [Default=100MB for webtoon and 400MB for others]")
|
|
||||||
|
|
||||||
outputOptions.add_option("-o", "--output", action="store", dest="output", default=None,
|
main_options.add_argument("-p", "--profile", action="store", dest="profile", default="KV",
|
||||||
help="Output generated file to specified directory or file")
|
help="Device profile (Available options: K1, K2, K34, K578, KDX, KPW, KPW5, KV, KO, "
|
||||||
outputOptions.add_option("-t", "--title", action="store", dest="title", default="defaulttitle",
|
"K11, KS, KoMT, KoG, KoGHD, KoA, KoAHD, KoAH2O, KoAO, KoN, KoC, KoL, KoF, KoS, KoE)"
|
||||||
help="Comic title [Default=filename or directory name]")
|
" [Default=KV]")
|
||||||
outputOptions.add_option("-f", "--format", action="store", dest="format", default="Auto",
|
main_options.add_argument("-m", "--manga-style", action="store_true", dest="righttoleft", default=False,
|
||||||
help="Output format (Available options: Auto, MOBI, EPUB, CBZ, KFX, MOBI+EPUB) "
|
help="Manga style (right-to-left reading and splitting)")
|
||||||
"[Default=Auto]")
|
main_options.add_argument("-q", "--hq", action="store_true", dest="hq", default=False,
|
||||||
outputOptions.add_option("-b", "--batchsplit", type="int", dest="batchsplit", default="0",
|
help="Try to increase the quality of magnification")
|
||||||
help="Split output into multiple files. 0: Don't split 1: Automatic mode "
|
main_options.add_argument("-2", "--two-panel", action="store_true", dest="autoscale", default=False,
|
||||||
"2: Consider every subdirectory as separate volume [Default=0]")
|
help="Display two not four panels in Panel View mode")
|
||||||
|
main_options.add_argument("-w", "--webtoon", action="store_true", dest="webtoon", default=False,
|
||||||
|
help="Webtoon processing mode"),
|
||||||
|
main_options.add_argument("--ts", "--targetsize", type=int, dest="targetsize", default=None,
|
||||||
|
help="the maximal size of output file in MB."
|
||||||
|
" [Default=100MB for webtoon and 400MB for others]")
|
||||||
|
|
||||||
processingOptions.add_option("-n", "--noprocessing", action="store_true", dest="noprocessing", default=False,
|
output_options.add_argument("-o", "--output", action="store", dest="output", default=None,
|
||||||
help="Do not modify image and ignore any profil or processing option")
|
help="Output generated file to specified directory or file")
|
||||||
processingOptions.add_option("-u", "--upscale", action="store_true", dest="upscale", default=False,
|
output_options.add_argument("-t", "--title", action="store", dest="title", default="defaulttitle",
|
||||||
help="Resize images smaller than device's resolution")
|
help="Comic title [Default=filename or directory name]")
|
||||||
processingOptions.add_option("-s", "--stretch", action="store_true", dest="stretch", default=False,
|
output_options.add_argument("-f", "--format", action="store", dest="format", default="Auto",
|
||||||
help="Stretch images to device's resolution")
|
help="Output format (Available options: Auto, MOBI, EPUB, CBZ, KFX, MOBI+EPUB) "
|
||||||
processingOptions.add_option("-r", "--splitter", type="int", dest="splitter", default="0",
|
"[Default=Auto]")
|
||||||
help="Double page parsing mode. 0: Split 1: Rotate 2: Both [Default=0]")
|
output_options.add_argument("-b", "--batchsplit", type=int, dest="batchsplit", default="0",
|
||||||
processingOptions.add_option("-g", "--gamma", type="float", dest="gamma", default="0.0",
|
help="Split output into multiple files. 0: Don't split 1: Automatic mode "
|
||||||
help="Apply gamma correction to linearize the image [Default=Auto]")
|
"2: Consider every subdirectory as separate volume [Default=0]")
|
||||||
processingOptions.add_option("-c", "--cropping", type="int", dest="cropping", default="2",
|
|
||||||
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("--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,
|
|
||||||
help="Disable autodetection and force white borders")
|
|
||||||
processingOptions.add_option("--forcecolor", action="store_true", dest="forcecolor", default=False,
|
|
||||||
help="Don't convert images to grayscale")
|
|
||||||
processingOptions.add_option("--forcepng", action="store_true", dest="forcepng", default=False,
|
|
||||||
help="Create PNG files instead JPEG")
|
|
||||||
processingOptions.add_option("--mozjpeg", action="store_true", dest="mozjpeg", default=False,
|
|
||||||
help="Create JPEG files using mozJpeg")
|
|
||||||
processingOptions.add_option("--maximizestrips", action="store_true", dest="maximizestrips", default=False,
|
|
||||||
help="Turn 1x4 strips to 2x2 strips")
|
|
||||||
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,
|
|
||||||
help="Replace screen height provided by device profile")
|
|
||||||
|
|
||||||
otherOptions.add_option("-h", "--help", action="help",
|
processing_options.add_argument("-n", "--noprocessing", action="store_true", dest="noprocessing", default=False,
|
||||||
help="Show this help message and exit")
|
help="Do not modify image and ignore any profil or processing option")
|
||||||
|
processing_options.add_argument("-u", "--upscale", action="store_true", dest="upscale", default=False,
|
||||||
|
help="Resize images smaller than device's resolution")
|
||||||
|
processing_options.add_argument("-s", "--stretch", action="store_true", dest="stretch", default=False,
|
||||||
|
help="Stretch images to device's resolution")
|
||||||
|
processing_options.add_argument("-r", "--splitter", type=int, dest="splitter", default="0",
|
||||||
|
help="Double page parsing mode. 0: Split 1: Rotate 2: Both [Default=0]")
|
||||||
|
processing_options.add_argument("-g", "--gamma", type=float, dest="gamma", default="0.0",
|
||||||
|
help="Apply gamma correction to linearize the image [Default=Auto]")
|
||||||
|
processing_options.add_argument("-c", "--cropping", type=int, dest="cropping", default="2",
|
||||||
|
help="Set cropping mode. 0: Disabled 1: Margins 2: Margins + page numbers [Default=2]")
|
||||||
|
processing_options.add_argument("--cp", "--croppingpower", type=float, dest="croppingp", default="1.0",
|
||||||
|
help="Set cropping power [Default=1.0]")
|
||||||
|
processing_options.add_argument("--cm", "--croppingminimum", type=float, dest="croppingm", default="0.0",
|
||||||
|
help="Set cropping minimum area ratio [Default=0.0]")
|
||||||
|
processing_options.add_argument("--blackborders", action="store_true", dest="black_borders", default=False,
|
||||||
|
help="Disable autodetection and force black borders")
|
||||||
|
processing_options.add_argument("--whiteborders", action="store_true", dest="white_borders", default=False,
|
||||||
|
help="Disable autodetection and force white borders")
|
||||||
|
processing_options.add_argument("--forcecolor", action="store_true", dest="forcecolor", default=False,
|
||||||
|
help="Don't convert images to grayscale")
|
||||||
|
processing_options.add_argument("--forcepng", action="store_true", dest="forcepng", default=False,
|
||||||
|
help="Create PNG files instead JPEG")
|
||||||
|
processing_options.add_argument("--mozjpeg", action="store_true", dest="mozjpeg", default=False,
|
||||||
|
help="Create JPEG files using mozJpeg")
|
||||||
|
processing_options.add_argument("--maximizestrips", action="store_true", dest="maximizestrips", default=False,
|
||||||
|
help="Turn 1x4 strips to 2x2 strips")
|
||||||
|
processing_options.add_argument("-d", "--delete", action="store_true", dest="delete", default=False,
|
||||||
|
help="Delete source file(s) or a directory. It's not recoverable.")
|
||||||
|
|
||||||
|
custom_profile_options.add_argument("--customwidth", type=int, dest="customwidth", default=0,
|
||||||
|
help="Replace screen width provided by device profile")
|
||||||
|
custom_profile_options.add_argument("--customheight", type=int, dest="customheight", default=0,
|
||||||
|
help="Replace screen height provided by device profile")
|
||||||
|
|
||||||
|
other_options.add_argument("-h", "--help", action="help",
|
||||||
|
help="Show this help message and exit")
|
||||||
|
|
||||||
psr.add_option_group(mainOptions)
|
|
||||||
psr.add_option_group(outputOptions)
|
|
||||||
psr.add_option_group(processingOptions)
|
|
||||||
psr.add_option_group(customProfileOptions)
|
|
||||||
psr.add_option_group(otherOptions)
|
|
||||||
return psr
|
return psr
|
||||||
|
|
||||||
|
|
||||||
def checkOptions(options):
|
def checkOptions(options):
|
||||||
options.panelview = True
|
options.panelview = True
|
||||||
options.iskindle = False
|
options.iskindle = False
|
||||||
|
options.isKobo = False
|
||||||
options.bordersColor = None
|
options.bordersColor = None
|
||||||
options.keep_epub = False
|
options.keep_epub = False
|
||||||
if options.format == 'EPUB-200MB':
|
if options.format == 'EPUB-200MB':
|
||||||
options.targetsize = 200
|
options.targetsize = 195
|
||||||
options.format = 'EPUB'
|
options.format = 'EPUB'
|
||||||
if options.batchsplit != 2:
|
if options.batchsplit != 2:
|
||||||
options.batchsplit = 1
|
options.batchsplit = 1
|
||||||
@@ -993,6 +1028,7 @@ def checkOptions(options):
|
|||||||
options.keep_epub = True
|
options.keep_epub = True
|
||||||
options.format = 'MOBI'
|
options.format = 'MOBI'
|
||||||
options.kfx = False
|
options.kfx = False
|
||||||
|
options.supportSyntheticSpread = False
|
||||||
if options.format == 'Auto':
|
if options.format == 'Auto':
|
||||||
if options.profile in ['K1', 'K2', 'K34', 'K578', 'KPW', 'KPW5', 'KV', 'KO', 'K11', 'KS']:
|
if options.profile in ['K1', 'K2', 'K34', 'K578', 'KPW', 'KPW5', 'KV', 'KO', 'K11', 'KS']:
|
||||||
options.format = 'MOBI'
|
options.format = 'MOBI'
|
||||||
@@ -1003,6 +1039,12 @@ def checkOptions(options):
|
|||||||
options.format = 'CBZ'
|
options.format = 'CBZ'
|
||||||
if options.profile in ['K1', 'K2', 'K34', 'K578', 'KPW', 'KPW5', 'KV', 'KO', 'K11', 'KS']:
|
if options.profile in ['K1', 'K2', 'K34', 'K578', 'KPW', 'KPW5', 'KV', 'KO', 'K11', 'KS']:
|
||||||
options.iskindle = True
|
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:
|
if options.white_borders:
|
||||||
options.bordersColor = 'white'
|
options.bordersColor = 'white'
|
||||||
if options.black_borders:
|
if options.black_borders:
|
||||||
@@ -1048,6 +1090,10 @@ def checkOptions(options):
|
|||||||
image.ProfileData.Profiles["Custom"] = newProfile
|
image.ProfileData.Profiles["Custom"] = newProfile
|
||||||
options.profile = "Custom"
|
options.profile = "Custom"
|
||||||
options.profileData = image.ProfileData.Profiles[options.profile]
|
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
|
return options
|
||||||
|
|
||||||
|
|
||||||
@@ -1103,7 +1149,7 @@ def makeBook(source, qtgui=None):
|
|||||||
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)
|
||||||
if options.noprocessing:
|
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:
|
else:
|
||||||
print("Processing images...")
|
print("Processing images...")
|
||||||
if GUI:
|
if GUI:
|
||||||
@@ -1112,8 +1158,6 @@ def makeBook(source, qtgui=None):
|
|||||||
if GUI:
|
if GUI:
|
||||||
GUI.progressBarTick.emit('1')
|
GUI.progressBarTick.emit('1')
|
||||||
chapterNames = sanitizeTree(os.path.join(path, 'OEBPS', 'Images'))
|
chapterNames = sanitizeTree(os.path.join(path, 'OEBPS', 'Images'))
|
||||||
if 'Ko' in options.profile and options.format == 'CBZ':
|
|
||||||
sanitizeTreeKobo(os.path.join(path, 'OEBPS', 'Images'))
|
|
||||||
if options.batchsplit > 0:
|
if options.batchsplit > 0:
|
||||||
tomes = splitDirectory(path)
|
tomes = splitDirectory(path)
|
||||||
else:
|
else:
|
||||||
@@ -1152,7 +1196,12 @@ def makeBook(source, qtgui=None):
|
|||||||
else:
|
else:
|
||||||
filepath.append(getOutputFilename(source, options.output, '.epub', ''))
|
filepath.append(getOutputFilename(source, options.output, '.epub', ''))
|
||||||
makeZIP(tome + '_comic', tome, True)
|
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)
|
rmtree(tome, True)
|
||||||
if GUI:
|
if GUI:
|
||||||
GUI.progressBarTick.emit('tick')
|
GUI.progressBarTick.emit('tick')
|
||||||
@@ -1179,6 +1228,12 @@ def makeBook(source, qtgui=None):
|
|||||||
os.remove(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])
|
||||||
|
if options.delete:
|
||||||
|
if os.path.isfile(source):
|
||||||
|
os.remove(source)
|
||||||
|
elif os.path.isdir(source):
|
||||||
|
rmtree(source)
|
||||||
|
|
||||||
return filepath
|
return filepath
|
||||||
|
|
||||||
|
|
||||||
@@ -1224,7 +1279,8 @@ def makeMOBIWorker(item):
|
|||||||
if kindlegenErrorCode > 0:
|
if kindlegenErrorCode > 0:
|
||||||
break
|
break
|
||||||
if ":I1036: Mobi file built successfully" in line:
|
if ":I1036: Mobi file built successfully" in line:
|
||||||
output.terminate()
|
output.communicate()
|
||||||
|
break
|
||||||
else:
|
else:
|
||||||
# ERROR: EPUB too big
|
# ERROR: EPUB too big
|
||||||
kindlegenErrorCode = 23026
|
kindlegenErrorCode = 23026
|
||||||
|
|||||||
@@ -20,8 +20,8 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
from argparse import ArgumentParser
|
||||||
from shutil import rmtree, copytree, move
|
from shutil import rmtree, copytree, move
|
||||||
from optparse import OptionParser, OptionGroup
|
|
||||||
from multiprocessing import Pool
|
from multiprocessing import Pool
|
||||||
from PIL import Image, ImageChops, ImageOps, ImageDraw
|
from PIL import Image, ImageChops, ImageOps, ImageDraw
|
||||||
from .shared import getImageFileName, walkLevel, walkSort, sanitizeTrace
|
from .shared import getImageFileName, walkLevel, walkSort, sanitizeTrace
|
||||||
@@ -102,7 +102,7 @@ def splitImage(work):
|
|||||||
opt = work[2]
|
opt = work[2]
|
||||||
filePath = os.path.join(path, name)
|
filePath = os.path.join(path, name)
|
||||||
Image.warnings.simplefilter('error', Image.DecompressionBombWarning)
|
Image.warnings.simplefilter('error', Image.DecompressionBombWarning)
|
||||||
Image.MAX_IMAGE_PIXELS = 1000000000
|
Image.MAX_IMAGE_PIXELS = 1000000000
|
||||||
imgOrg = Image.open(filePath).convert('RGB')
|
imgOrg = Image.open(filePath).convert('RGB')
|
||||||
imgProcess = Image.open(filePath).convert('1')
|
imgProcess = Image.open(filePath).convert('1')
|
||||||
widthImg, heightImg = imgOrg.size
|
widthImg, heightImg = imgOrg.size
|
||||||
@@ -116,7 +116,7 @@ def splitImage(work):
|
|||||||
panelDetected = False
|
panelDetected = False
|
||||||
panels = []
|
panels = []
|
||||||
while yWork < heightImg:
|
while yWork < heightImg:
|
||||||
tmpImg = imgProcess.crop([4, yWork, widthImg-4, yWork + 4])
|
tmpImg = imgProcess.crop((4, yWork, widthImg-4, yWork + 4))
|
||||||
solid = detectSolid(tmpImg)
|
solid = detectSolid(tmpImg)
|
||||||
if not solid and not panelDetected:
|
if not solid and not panelDetected:
|
||||||
panelDetected = True
|
panelDetected = True
|
||||||
@@ -149,7 +149,7 @@ def splitImage(work):
|
|||||||
|
|
||||||
if opt.debug:
|
if opt.debug:
|
||||||
for panel in panelsProcessed:
|
for panel in panelsProcessed:
|
||||||
draw.rectangle([(0, panel[0]), (widthImg, panel[1])], (0, 255, 0, 128), (0, 0, 255, 255))
|
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 = Image.alpha_composite(imgOrg.convert(mode='RGBA'), drawImg)
|
||||||
debugImage.save(os.path.join(path, os.path.splitext(name)[0] + '-debug.png'), 'PNG')
|
debugImage.save(os.path.join(path, os.path.splitext(name)[0] + '-debug.png'), 'PNG')
|
||||||
|
|
||||||
@@ -182,7 +182,7 @@ def splitImage(work):
|
|||||||
if pageHeight > 15:
|
if pageHeight > 15:
|
||||||
newPage = Image.new('RGB', (widthImg, pageHeight))
|
newPage = Image.new('RGB', (widthImg, pageHeight))
|
||||||
for panel in page:
|
for panel in page:
|
||||||
panelImg = imgOrg.crop([0, panelsProcessed[panel][0], widthImg, panelsProcessed[panel][1]])
|
panelImg = imgOrg.crop((0, panelsProcessed[panel][0], widthImg, panelsProcessed[panel][1]))
|
||||||
newPage.paste(panelImg, (0, targetHeight))
|
newPage.paste(panelImg, (0, targetHeight))
|
||||||
targetHeight += panelsProcessed[panel][2]
|
targetHeight += panelsProcessed[panel][2]
|
||||||
newPage.save(os.path.join(path, os.path.splitext(name)[0] + '-' + str(pageNumber) + '.png'), 'PNG')
|
newPage.save(os.path.join(path, os.path.splitext(name)[0] + '-' + str(pageNumber) + '.png'), 'PNG')
|
||||||
@@ -193,97 +193,100 @@ def splitImage(work):
|
|||||||
|
|
||||||
|
|
||||||
def main(argv=None, qtgui=None):
|
def main(argv=None, qtgui=None):
|
||||||
global options, GUI, splitWorkerPool, splitWorkerOutput, mergeWorkerPool, mergeWorkerOutput
|
global args, GUI, splitWorkerPool, splitWorkerOutput, mergeWorkerPool, mergeWorkerOutput
|
||||||
parser = OptionParser(usage="Usage: kcc-c2p [options] comic_folder", add_help_option=False)
|
parser = ArgumentParser(prog="kcc-c2p", usage="kcc-c2p [options] [input]", add_help=False)
|
||||||
mainOptions = OptionGroup(parser, "MANDATORY")
|
|
||||||
otherOptions = OptionGroup(parser, "OTHER")
|
mandatory_options = parser.add_argument_group("MANDATORY")
|
||||||
mainOptions.add_option("-y", "--height", type="int", dest="height", default=0,
|
main_options = parser.add_argument_group("MAIN")
|
||||||
help="Height of the target device screen")
|
other_options = parser.add_argument_group("OTHER")
|
||||||
mainOptions.add_option("-i", "--in-place", action="store_true", dest="inPlace", default=False,
|
mandatory_options.add_argument("input", action="extend", nargs="*", default=None,
|
||||||
help="Overwrite source directory")
|
help="Full path to comic folder(s) to be processed. Separate multiple inputs"
|
||||||
mainOptions.add_option("-m", "--merge", action="store_true", dest="merge", default=False,
|
" with spaces.")
|
||||||
help="Combine every directory into a single image before splitting")
|
main_options.add_argument("-y", "--height", type=int, dest="height", default=0,
|
||||||
otherOptions.add_option("-d", "--debug", action="store_true", dest="debug", default=False,
|
help="Height of the target device screen")
|
||||||
help="Create debug file for every split image")
|
main_options.add_argument("-i", "--in-place", action="store_true", dest="inPlace", default=False,
|
||||||
otherOptions.add_option("-h", "--help", action="help",
|
help="Overwrite source directory")
|
||||||
help="Show this help message and exit")
|
main_options.add_argument("-m", "--merge", action="store_true", dest="merge", default=False,
|
||||||
parser.add_option_group(mainOptions)
|
help="Combine every directory into a single image before splitting")
|
||||||
parser.add_option_group(otherOptions)
|
other_options.add_argument("-d", "--debug", action="store_true", dest="debug", default=False,
|
||||||
options, args = parser.parse_args(argv)
|
help="Create debug file for every split image")
|
||||||
|
other_options.add_argument("-h", "--help", action="help",
|
||||||
|
help="Show this help message and exit")
|
||||||
|
args = parser.parse_args(argv)
|
||||||
if qtgui:
|
if qtgui:
|
||||||
GUI = qtgui
|
GUI = qtgui
|
||||||
else:
|
else:
|
||||||
GUI = None
|
GUI = None
|
||||||
if len(args) != 1:
|
if not argv or args.input == []:
|
||||||
parser.print_help()
|
parser.print_help()
|
||||||
return 1
|
return 1
|
||||||
if options.height > 0:
|
if args.height > 0:
|
||||||
options.sourceDir = args[0]
|
for sourceDir in args.input:
|
||||||
options.targetDir = args[0] + "-Splitted"
|
targetDir = sourceDir + "-Splitted"
|
||||||
if os.path.isdir(options.sourceDir):
|
if os.path.isdir(sourceDir):
|
||||||
rmtree(options.targetDir, True)
|
rmtree(targetDir, True)
|
||||||
copytree(options.sourceDir, options.targetDir)
|
copytree(sourceDir, targetDir)
|
||||||
work = []
|
work = []
|
||||||
pagenumber = 1
|
pagenumber = 1
|
||||||
splitWorkerOutput = []
|
splitWorkerOutput = []
|
||||||
splitWorkerPool = Pool(maxtasksperchild=10)
|
splitWorkerPool = Pool(maxtasksperchild=10)
|
||||||
if options.merge:
|
if args.merge:
|
||||||
print("Merging images...")
|
print("Merging images...")
|
||||||
directoryNumer = 1
|
directoryNumer = 1
|
||||||
mergeWork = []
|
mergeWork = []
|
||||||
mergeWorkerOutput = []
|
mergeWorkerOutput = []
|
||||||
mergeWorkerPool = Pool(maxtasksperchild=10)
|
mergeWorkerPool = Pool(maxtasksperchild=10)
|
||||||
mergeWork.append([options.targetDir])
|
mergeWork.append([targetDir])
|
||||||
for root, dirs, files in os.walk(options.targetDir, False):
|
for root, dirs, files in os.walk(targetDir, False):
|
||||||
dirs, files = walkSort(dirs, files)
|
dirs, files = walkSort(dirs, files)
|
||||||
for directory in dirs:
|
for directory in dirs:
|
||||||
directoryNumer += 1
|
directoryNumer += 1
|
||||||
mergeWork.append([os.path.join(root, directory)])
|
mergeWork.append([os.path.join(root, directory)])
|
||||||
|
if GUI:
|
||||||
|
GUI.progressBarTick.emit('Combining images')
|
||||||
|
GUI.progressBarTick.emit(str(directoryNumer))
|
||||||
|
for i in mergeWork:
|
||||||
|
mergeWorkerPool.apply_async(func=mergeDirectory, args=(i, ), callback=mergeDirectoryTick)
|
||||||
|
mergeWorkerPool.close()
|
||||||
|
mergeWorkerPool.join()
|
||||||
|
if GUI and not GUI.conversionAlive:
|
||||||
|
rmtree(targetDir, True)
|
||||||
|
raise UserWarning("Conversion interrupted.")
|
||||||
|
if len(mergeWorkerOutput) > 0:
|
||||||
|
rmtree(targetDir, True)
|
||||||
|
raise RuntimeError("One of workers crashed. Cause: " + mergeWorkerOutput[0][0],
|
||||||
|
mergeWorkerOutput[0][1])
|
||||||
|
print("Splitting images...")
|
||||||
|
for root, _, files in os.walk(targetDir, False):
|
||||||
|
for name in files:
|
||||||
|
if getImageFileName(name) is not None:
|
||||||
|
pagenumber += 1
|
||||||
|
work.append([root, name, args])
|
||||||
|
else:
|
||||||
|
os.remove(os.path.join(root, name))
|
||||||
if GUI:
|
if GUI:
|
||||||
GUI.progressBarTick.emit('Combining images')
|
GUI.progressBarTick.emit('Splitting images')
|
||||||
GUI.progressBarTick.emit(str(directoryNumer))
|
GUI.progressBarTick.emit(str(pagenumber))
|
||||||
for i in mergeWork:
|
GUI.progressBarTick.emit('tick')
|
||||||
mergeWorkerPool.apply_async(func=mergeDirectory, args=(i, ), callback=mergeDirectoryTick)
|
if len(work) > 0:
|
||||||
mergeWorkerPool.close()
|
for i in work:
|
||||||
mergeWorkerPool.join()
|
splitWorkerPool.apply_async(func=splitImage, args=(i, ), callback=splitImageTick)
|
||||||
if GUI and not GUI.conversionAlive:
|
splitWorkerPool.close()
|
||||||
rmtree(options.targetDir, True)
|
splitWorkerPool.join()
|
||||||
raise UserWarning("Conversion interrupted.")
|
if GUI and not GUI.conversionAlive:
|
||||||
if len(mergeWorkerOutput) > 0:
|
rmtree(targetDir, True)
|
||||||
rmtree(options.targetDir, True)
|
raise UserWarning("Conversion interrupted.")
|
||||||
raise RuntimeError("One of workers crashed. Cause: " + mergeWorkerOutput[0][0],
|
if len(splitWorkerOutput) > 0:
|
||||||
mergeWorkerOutput[0][1])
|
rmtree(targetDir, True)
|
||||||
print("Splitting images...")
|
raise RuntimeError("One of workers crashed. Cause: " + splitWorkerOutput[0][0],
|
||||||
for root, _, files in os.walk(options.targetDir, False):
|
splitWorkerOutput[0][1])
|
||||||
for name in files:
|
if args.inPlace:
|
||||||
if getImageFileName(name) is not None:
|
rmtree(sourceDir)
|
||||||
pagenumber += 1
|
move(targetDir, sourceDir)
|
||||||
work.append([root, name, options])
|
else:
|
||||||
else:
|
rmtree(targetDir, True)
|
||||||
os.remove(os.path.join(root, name))
|
raise UserWarning("Source directory is empty.")
|
||||||
if GUI:
|
|
||||||
GUI.progressBarTick.emit('Splitting images')
|
|
||||||
GUI.progressBarTick.emit(str(pagenumber))
|
|
||||||
GUI.progressBarTick.emit('tick')
|
|
||||||
if len(work) > 0:
|
|
||||||
for i in work:
|
|
||||||
splitWorkerPool.apply_async(func=splitImage, args=(i, ), callback=splitImageTick)
|
|
||||||
splitWorkerPool.close()
|
|
||||||
splitWorkerPool.join()
|
|
||||||
if GUI and not GUI.conversionAlive:
|
|
||||||
rmtree(options.targetDir, True)
|
|
||||||
raise UserWarning("Conversion interrupted.")
|
|
||||||
if len(splitWorkerOutput) > 0:
|
|
||||||
rmtree(options.targetDir, True)
|
|
||||||
raise RuntimeError("One of workers crashed. Cause: " + splitWorkerOutput[0][0],
|
|
||||||
splitWorkerOutput[0][1])
|
|
||||||
if options.inPlace:
|
|
||||||
rmtree(options.sourceDir)
|
|
||||||
move(options.targetDir, options.sourceDir)
|
|
||||||
else:
|
else:
|
||||||
rmtree(options.targetDir, True)
|
raise UserWarning("Provided input is not a directory.")
|
||||||
raise UserWarning("Source directory is empty.")
|
|
||||||
else:
|
|
||||||
raise UserWarning("Provided path is not a directory.")
|
|
||||||
else:
|
else:
|
||||||
raise UserWarning("Target height is not set.")
|
raise UserWarning("Target height is not set.")
|
||||||
|
|||||||
@@ -19,6 +19,9 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import platform
|
||||||
|
import subprocess
|
||||||
|
import distro
|
||||||
from psutil import Popen
|
from psutil import Popen
|
||||||
from shutil import move
|
from shutil import move
|
||||||
from subprocess import STDOUT, PIPE
|
from subprocess import STDOUT, PIPE
|
||||||
@@ -38,19 +41,39 @@ class ComicArchive:
|
|||||||
self.type = line.rstrip().decode().split(' = ')[1].upper()
|
self.type = line.rstrip().decode().split(' = ')[1].upper()
|
||||||
break
|
break
|
||||||
process.communicate()
|
process.communicate()
|
||||||
if process.returncode != 0:
|
if process.returncode != 0 and distro.id() == 'fedora':
|
||||||
raise OSError('Archive is corrupted or encrypted.')
|
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']:
|
elif self.type not in ['7Z', 'RAR', 'RAR5', 'ZIP']:
|
||||||
raise OSError('Unsupported archive format.')
|
raise OSError('Unsupported archive format.')
|
||||||
|
|
||||||
def extract(self, targetdir):
|
def extract(self, targetdir):
|
||||||
if not os.path.isdir(targetdir):
|
if not os.path.isdir(targetdir):
|
||||||
raise OSError('Target directory don\'t exist.')
|
raise OSError('Target directory doesn\'t exist.')
|
||||||
process = Popen('7z x -y -xr!__MACOSX -xr!.DS_Store -xr!thumbs.db -xr!Thumbs.db -o"' + targetdir + '" "' +
|
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)
|
self.filepath + '"', stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=True)
|
||||||
process.communicate()
|
process.communicate()
|
||||||
if process.returncode != 0:
|
if process.returncode != 0 and distro.id() == 'fedora':
|
||||||
raise OSError('Failed to extract archive.')
|
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 and platform.system() == 'Darwin':
|
||||||
|
process = subprocess.run(f"unar '{self.filepath}' -f -o '{targetdir}'",
|
||||||
|
stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=True)
|
||||||
|
if process.returncode != 0:
|
||||||
|
raise Exception(process.stdout.decode("utf-8"))
|
||||||
|
elif process.returncode != 0:
|
||||||
|
raise OSError('Failed to extract archive. Check if p7zip-rar is installed.')
|
||||||
tdir = os.listdir(targetdir)
|
tdir = os.listdir(targetdir)
|
||||||
if 'ComicInfo.xml' in tdir:
|
if 'ComicInfo.xml' in tdir:
|
||||||
tdir.remove('ComicInfo.xml')
|
tdir.remove('ComicInfo.xml')
|
||||||
|
|||||||
@@ -24,6 +24,13 @@ import mozjpeg_lossless_optimization
|
|||||||
from PIL import Image, ImageOps, ImageStat, ImageChops, ImageFilter
|
from PIL import Image, ImageOps, ImageStat, ImageChops, ImageFilter
|
||||||
from .shared import md5Checksum
|
from .shared import md5Checksum
|
||||||
|
|
||||||
|
# 0.045 was determined by
|
||||||
|
# 1200 / 824 = 1.456 (Kindle DX resolution)
|
||||||
|
# 2250 / 1500 = 1.5 (Typical manga page resolution)
|
||||||
|
# 1.5 - 1.456 < 0.045
|
||||||
|
# 0.045 / 1.5 = 0.03 (So maximum 3% of is cropped)
|
||||||
|
AUTO_CROP_THRESHOLD = 0.045
|
||||||
|
|
||||||
|
|
||||||
class ProfileData:
|
class ProfileData:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@@ -115,10 +122,10 @@ class ComicPageParser:
|
|||||||
self.image = Image.open(os.path.join(source[0], source[1])).convert('RGB')
|
self.image = Image.open(os.path.join(source[0], source[1])).convert('RGB')
|
||||||
self.color = self.colorCheck()
|
self.color = self.colorCheck()
|
||||||
self.fill = self.fillCheck()
|
self.fill = self.fillCheck()
|
||||||
self.splitCheck()
|
|
||||||
# backwards compatibility for Pillow >9.1.0
|
# backwards compatibility for Pillow >9.1.0
|
||||||
if not hasattr(Image, 'Resampling'):
|
if not hasattr(Image, 'Resampling'):
|
||||||
Image.Resampling = Image
|
Image.Resampling = Image
|
||||||
|
self.splitCheck()
|
||||||
|
|
||||||
def getImageHistogram(self, image):
|
def getImageHistogram(self, image):
|
||||||
histogram = image.histogram()
|
histogram = image.histogram()
|
||||||
@@ -265,6 +272,7 @@ class ComicPage:
|
|||||||
if self.fill != 'white':
|
if self.fill != 'white':
|
||||||
flags.append('BlackBackground')
|
flags.append('BlackBackground')
|
||||||
if self.opt.forcepng:
|
if self.opt.forcepng:
|
||||||
|
self.image.info["transparency"] = None
|
||||||
self.targetPath += '.png'
|
self.targetPath += '.png'
|
||||||
self.image.save(self.targetPath, 'PNG', optimize=1)
|
self.image.save(self.targetPath, 'PNG', optimize=1)
|
||||||
else:
|
else:
|
||||||
@@ -305,36 +313,32 @@ class ComicPage:
|
|||||||
self.image = self.image.quantize(palette=palImg)
|
self.image = self.image.quantize(palette=palImg)
|
||||||
|
|
||||||
def resizeImage(self):
|
def resizeImage(self):
|
||||||
if self.image.size[0] <= self.size[0] and self.image.size[1] <= self.size[1]:
|
ratio_device = float(self.size[1]) / float(self.size[0])
|
||||||
method = Image.Resampling.BICUBIC
|
ratio_image = float(self.image.size[1]) / float(self.image.size[0])
|
||||||
else:
|
method = self.resize_method()
|
||||||
method = Image.Resampling.LANCZOS
|
|
||||||
if self.opt.stretch:
|
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 method == Image.Resampling.BICUBIC and not self.opt.upscale:
|
||||||
if self.opt.format == 'CBZ' or self.opt.kfx:
|
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.Resampling.BICUBIC, centering=(0.5, 0.5))
|
self.image = ImageOps.fit(self.image, self.size, method=method)
|
||||||
else:
|
else: # if image bigger than device resolution or smaller with upscaling
|
||||||
if self.opt.format == 'CBZ' or self.opt.kfx:
|
if abs(ratio_image - ratio_device) < AUTO_CROP_THRESHOLD:
|
||||||
ratioDev = float(self.size[0]) / float(self.size[1])
|
self.image = ImageOps.fit(self.image, self.size, method=method)
|
||||||
if (float(self.image.size[0]) / float(self.image.size[1])) < ratioDev:
|
elif self.opt.format == 'CBZ' or self.opt.kfx:
|
||||||
diff = int(self.image.size[1] * ratioDev) - self.image.size[0]
|
self.image = ImageOps.pad(self.image, self.size, method=method, color=self.fill)
|
||||||
self.image = ImageOps.expand(self.image, border=(int(diff / 2), 0), fill=self.fill)
|
|
||||||
elif (float(self.image.size[0]) / float(self.image.size[1])) > ratioDev:
|
|
||||||
diff = int(self.image.size[0] / ratioDev) - self.image.size[1]
|
|
||||||
self.image = ImageOps.expand(self.image, border=(0, int(diff / 2)), fill=self.fill)
|
|
||||||
self.image = ImageOps.fit(self.image, self.size, method=method, centering=(0.5, 0.5))
|
|
||||||
else:
|
else:
|
||||||
hpercent = self.size[1] / float(self.image.size[1])
|
self.image = ImageOps.contain(self.image, self.size, method=method)
|
||||||
wsize = int((float(self.image.size[0]) * float(hpercent)))
|
|
||||||
self.image = self.image.resize((wsize, self.size[1]), method)
|
def resize_method(self):
|
||||||
if self.image.size[0] > self.size[0] or self.image.size[1] > self.size[1]:
|
if self.image.size[0] <= self.size[0] and self.image.size[1] <= self.size[1]:
|
||||||
self.image.thumbnail(self.size, Image.Resampling.LANCZOS)
|
method = Image.Resampling.BICUBIC
|
||||||
|
else:
|
||||||
|
method = Image.Resampling.LANCZOS
|
||||||
|
return method
|
||||||
|
|
||||||
def getBoundingBox(self, tmptmg):
|
def getBoundingBox(self, tmptmg):
|
||||||
min_margin = [int(0.005 * i + 0.5) for i in tmptmg.size]
|
min_margin = [int(0.005 * i + 0.5) for i in tmptmg.size]
|
||||||
@@ -350,7 +354,13 @@ class ComicPage:
|
|||||||
)
|
)
|
||||||
return bbox
|
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':
|
if self.fill != 'white':
|
||||||
tmptmg = self.image.convert(mode='L')
|
tmptmg = self.image.convert(mode='L')
|
||||||
else:
|
else:
|
||||||
@@ -359,16 +369,18 @@ class ComicPage:
|
|||||||
tmptmg = tmptmg.filter(ImageFilter.MinFilter(size=3))
|
tmptmg = tmptmg.filter(ImageFilter.MinFilter(size=3))
|
||||||
tmptmg = tmptmg.filter(ImageFilter.GaussianBlur(radius=5))
|
tmptmg = tmptmg.filter(ImageFilter.GaussianBlur(radius=5))
|
||||||
tmptmg = tmptmg.point(lambda x: (x >= 16 * power) and x)
|
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':
|
if self.fill != 'white':
|
||||||
tmptmg = self.image.convert(mode='L')
|
tmptmg = self.image.convert(mode='L')
|
||||||
else:
|
else:
|
||||||
tmptmg = ImageOps.invert(self.image.convert(mode='L'))
|
tmptmg = ImageOps.invert(self.image.convert(mode='L'))
|
||||||
tmptmg = tmptmg.filter(ImageFilter.GaussianBlur(radius=3))
|
tmptmg = tmptmg.filter(ImageFilter.GaussianBlur(radius=3))
|
||||||
tmptmg = tmptmg.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(tmptmg)) if tmptmg.getbbox() else self.image
|
if tmptmg.getbbox():
|
||||||
|
self.maybeCrop(self.getBoundingBox(tmptmg), minimum)
|
||||||
|
|
||||||
|
|
||||||
class Cover:
|
class Cover:
|
||||||
@@ -381,10 +393,10 @@ class Cover:
|
|||||||
else:
|
else:
|
||||||
self.tomeid = tomeid
|
self.tomeid = tomeid
|
||||||
self.image = Image.open(source)
|
self.image = Image.open(source)
|
||||||
self.process()
|
|
||||||
# backwards compatibility for Pillow >9.1.0
|
# backwards compatibility for Pillow >9.1.0
|
||||||
if not hasattr(Image, 'Resampling'):
|
if not hasattr(Image, 'Resampling'):
|
||||||
Image.Resampling = Image
|
Image.Resampling = Image
|
||||||
|
self.process()
|
||||||
|
|
||||||
def process(self):
|
def process(self):
|
||||||
self.image = self.image.convert('RGB')
|
self.image = self.image.convert('RGB')
|
||||||
|
|||||||
@@ -34,7 +34,8 @@ class MetadataParser:
|
|||||||
'Inkers': [],
|
'Inkers': [],
|
||||||
'Colorists': [],
|
'Colorists': [],
|
||||||
'Summary': '',
|
'Summary': '',
|
||||||
'Bookmarks': []}
|
'Bookmarks': [],
|
||||||
|
'Title': ''}
|
||||||
self.rawdata = None
|
self.rawdata = None
|
||||||
self.format = None
|
self.format = None
|
||||||
if self.source.endswith('.xml') and os.path.exists(self.source):
|
if self.source.endswith('.xml') and os.path.exists(self.source):
|
||||||
@@ -45,7 +46,7 @@ class MetadataParser:
|
|||||||
self.rawdata = cbx.extractMetadata()
|
self.rawdata = cbx.extractMetadata()
|
||||||
self.format = cbx.type
|
self.format = cbx.type
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
raise UserWarning(e.strerror)
|
raise UserWarning(e)
|
||||||
if self.rawdata:
|
if self.rawdata:
|
||||||
self.parseXML()
|
self.parseXML()
|
||||||
|
|
||||||
@@ -58,6 +59,8 @@ class MetadataParser:
|
|||||||
self.data['Number'] = self.rawdata.getElementsByTagName('Number')[0].firstChild.nodeValue
|
self.data['Number'] = self.rawdata.getElementsByTagName('Number')[0].firstChild.nodeValue
|
||||||
if len(self.rawdata.getElementsByTagName('Summary')) != 0:
|
if len(self.rawdata.getElementsByTagName('Summary')) != 0:
|
||||||
self.data['Summary'] = self.rawdata.getElementsByTagName('Summary')[0].firstChild.nodeValue
|
self.data['Summary'] = self.rawdata.getElementsByTagName('Summary')[0].firstChild.nodeValue
|
||||||
|
if len(self.rawdata.getElementsByTagName('Title')) != 0:
|
||||||
|
self.data['Title'] = self.rawdata.getElementsByTagName('Title')[0].firstChild.nodeValue
|
||||||
for field in ['Writer', 'Penciller', 'Inker', 'Colorist']:
|
for field in ['Writer', 'Penciller', 'Inker', 'Colorist']:
|
||||||
if len(self.rawdata.getElementsByTagName(field)) != 0:
|
if len(self.rawdata.getElementsByTagName(field)) != 0:
|
||||||
for person in self.rawdata.getElementsByTagName(field)[0].firstChild.nodeValue.split(', '):
|
for person in self.rawdata.getElementsByTagName(field)[0].firstChild.nodeValue.split(', '):
|
||||||
@@ -76,7 +79,8 @@ class MetadataParser:
|
|||||||
for row in (['Series', self.data['Series']], ['Volume', self.data['Volume']],
|
for row in (['Series', self.data['Series']], ['Volume', self.data['Volume']],
|
||||||
['Number', self.data['Number']], ['Writer', ', '.join(self.data['Writers'])],
|
['Number', self.data['Number']], ['Writer', ', '.join(self.data['Writers'])],
|
||||||
['Penciller', ', '.join(self.data['Pencillers'])], ['Inker', ', '.join(self.data['Inkers'])],
|
['Penciller', ', '.join(self.data['Pencillers'])], ['Inker', ', '.join(self.data['Inkers'])],
|
||||||
['Colorist', ', '.join(self.data['Colorists'])], ['Summary', self.data['Summary']]):
|
['Colorist', ', '.join(self.data['Colorists'])], ['Summary', self.data['Summary']],
|
||||||
|
['Title', self.data['Title']]):
|
||||||
if self.rawdata.getElementsByTagName(row[0]):
|
if self.rawdata.getElementsByTagName(row[0]):
|
||||||
node = self.rawdata.getElementsByTagName(row[0])[0]
|
node = self.rawdata.getElementsByTagName(row[0])[0]
|
||||||
if row[1]:
|
if row[1]:
|
||||||
@@ -97,7 +101,8 @@ class MetadataParser:
|
|||||||
for row in (['Series', self.data['Series']], ['Volume', self.data['Volume']],
|
for row in (['Series', self.data['Series']], ['Volume', self.data['Volume']],
|
||||||
['Number', self.data['Number']], ['Writer', ', '.join(self.data['Writers'])],
|
['Number', self.data['Number']], ['Writer', ', '.join(self.data['Writers'])],
|
||||||
['Penciller', ', '.join(self.data['Pencillers'])], ['Inker', ', '.join(self.data['Inkers'])],
|
['Penciller', ', '.join(self.data['Pencillers'])], ['Inker', ', '.join(self.data['Inkers'])],
|
||||||
['Colorist', ', '.join(self.data['Colorists'])], ['Summary', self.data['Summary']]):
|
['Colorist', ', '.join(self.data['Colorists'])], ['Summary', self.data['Summary']],
|
||||||
|
['Title', self.data['Title']]):
|
||||||
if row[1]:
|
if row[1]:
|
||||||
main = doc.createElement(row[0])
|
main = doc.createElement(row[0])
|
||||||
root.appendChild(main)
|
root.appendChild(main)
|
||||||
@@ -116,5 +121,5 @@ class MetadataParser:
|
|||||||
cbx = comicarchive.ComicArchive(self.source)
|
cbx = comicarchive.ComicArchive(self.source)
|
||||||
cbx.addFile(tmpXML)
|
cbx.addFile(tmpXML)
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
raise UserWarning(e.strerror)
|
raise UserWarning(e)
|
||||||
rmtree(workdir)
|
rmtree(workdir)
|
||||||
|
|||||||
@@ -25,6 +25,11 @@ import os
|
|||||||
from random import choice
|
from random import choice
|
||||||
from string import ascii_uppercase, digits
|
from string import ascii_uppercase, digits
|
||||||
|
|
||||||
|
# skip stray images a few pixels in size in some PDFs
|
||||||
|
# typical images are many thousands in length
|
||||||
|
# https://github.com/ciromattia/kcc/pull/546
|
||||||
|
STRAY_IMAGE_LENGTH_THRESHOLD = 300
|
||||||
|
|
||||||
|
|
||||||
class PdfJpgExtract:
|
class PdfJpgExtract:
|
||||||
def __init__(self, fname):
|
def __init__(self, fname):
|
||||||
@@ -60,10 +65,15 @@ class PdfJpgExtract:
|
|||||||
raise Exception("Didn't find end of JPG!")
|
raise Exception("Didn't find end of JPG!")
|
||||||
istart += startfix
|
istart += startfix
|
||||||
iend += endfix
|
iend += endfix
|
||||||
|
i = iend
|
||||||
|
|
||||||
|
if iend - istart < STRAY_IMAGE_LENGTH_THRESHOLD:
|
||||||
|
continue
|
||||||
|
|
||||||
jpg = pdf[istart:iend]
|
jpg = pdf[istart:iend]
|
||||||
jpgfile = open(self.path + "/jpg%d.jpg" % njpg, "wb")
|
jpgfile = open(self.path + "/jpg%d.jpg" % njpg, "wb")
|
||||||
jpgfile.write(jpg)
|
jpgfile.write(jpg)
|
||||||
jpgfile.close()
|
jpgfile.close()
|
||||||
njpg += 1
|
njpg += 1
|
||||||
i = iend
|
|
||||||
return self.path, njpg
|
return self.path, njpg
|
||||||
|
|||||||
BIN
other/osx/7z
BIN
other/osx/7z
Binary file not shown.
BIN
other/osx/7z.so
BIN
other/osx/7z.so
Binary file not shown.
@@ -1,72 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>CFBundleDevelopmentRegion</key>
|
|
||||||
<string>English</string>
|
|
||||||
<key>CFBundleDisplayName</key>
|
|
||||||
<string>Kindle Comic Converter</string>
|
|
||||||
<key>CFBundleDocumentTypes</key>
|
|
||||||
<array>
|
|
||||||
<dict>
|
|
||||||
<key>CFBundleTypeExtensions</key>
|
|
||||||
<array>
|
|
||||||
<string>cbz</string>
|
|
||||||
<string>cbr</string>
|
|
||||||
<string>cb7</string>
|
|
||||||
<string>zip</string>
|
|
||||||
<string>rar</string>
|
|
||||||
<string>7z</string>
|
|
||||||
<string>pdf</string>
|
|
||||||
</array>
|
|
||||||
<key>CFBundleTypeIconFile</key>
|
|
||||||
<string>comic2ebook.icns</string>
|
|
||||||
<key>CFBundleTypeName</key>
|
|
||||||
<string>Comics</string>
|
|
||||||
<key>CFBundleTypeRole</key>
|
|
||||||
<string>Editor</string>
|
|
||||||
</dict>
|
|
||||||
</array>
|
|
||||||
<key>CFBundleExecutable</key>
|
|
||||||
<string>MacOS/Kindle Comic Converter</string>
|
|
||||||
<key>CFBundleGetInfoString</key>
|
|
||||||
<string>KindleComicConverter 5.5.2, written 2012-2019 by Ciro Mattia Gonano and Pawel Jastrzebski</string>
|
|
||||||
<key>CFBundleIconFile</key>
|
|
||||||
<string>comic2ebook.icns</string>
|
|
||||||
<key>CFBundleIdentifier</key>
|
|
||||||
<string>com.kindlecomicconverter.KindleComicConverter</string>
|
|
||||||
<key>CFBundleInfoDictionaryVersion</key>
|
|
||||||
<string>6.0</string>
|
|
||||||
<key>CFBundleName</key>
|
|
||||||
<string>Kindle Comic Converter</string>
|
|
||||||
<key>CFBundlePackageType</key>
|
|
||||||
<string>APPL</string>
|
|
||||||
<key>CFBundleShortVersionString</key>
|
|
||||||
<string>5.5.2</string>
|
|
||||||
<key>CFBundleSignature</key>
|
|
||||||
<string>????</string>
|
|
||||||
<key>CFBundleVersion</key>
|
|
||||||
<string>5.5.2</string>
|
|
||||||
<key>LSEnvironment</key>
|
|
||||||
<dict>
|
|
||||||
<key>PATH</key>
|
|
||||||
<string>./../Resources:/Applications/Kindle Comic Creator/Kindle Comic Creator.app/Contents/MacOS:/usr/local/bin:/usr/bin:/bin</string>
|
|
||||||
</dict>
|
|
||||||
<key>LSHasLocalizedDisplayName</key>
|
|
||||||
<false/>
|
|
||||||
<key>LSMinimumSystemVersion</key>
|
|
||||||
<string>10.14.0</string>
|
|
||||||
<key>NSAppleScriptEnabled</key>
|
|
||||||
<false/>
|
|
||||||
<key>NSHumanReadableCopyright</key>
|
|
||||||
<string>ISC License (ISCL)</string>
|
|
||||||
<key>NSMainNibFile</key>
|
|
||||||
<string>MainMenu</string>
|
|
||||||
<key>NSPrincipalClass</key>
|
|
||||||
<string>NSApplication</string>
|
|
||||||
<key>NSRequiresAquaSystemAppearance</key>
|
|
||||||
<string>false</string>
|
|
||||||
<key>NSInitialToolTipDelay</key>
|
|
||||||
<integer>1000</integer>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
BIN
other/osx/Rar.so
BIN
other/osx/Rar.so
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,90 +0,0 @@
|
|||||||
7-Zip
|
|
||||||
~~~~~
|
|
||||||
License for use and distribution
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
7-Zip Copyright (C) 1999-2018 Igor Pavlov.
|
|
||||||
|
|
||||||
The licenses for files are:
|
|
||||||
|
|
||||||
1) 7z.dll:
|
|
||||||
- The "GNU LGPL" as main license for most of the code
|
|
||||||
- The "GNU LGPL" with "unRAR license restriction" for some code
|
|
||||||
- The "BSD 3-clause License" for some code
|
|
||||||
2) All other files: the "GNU LGPL".
|
|
||||||
|
|
||||||
Redistributions in binary form must reproduce related license information from this file.
|
|
||||||
|
|
||||||
Note:
|
|
||||||
You can use 7-Zip on any computer, including a computer in a commercial
|
|
||||||
organization. You don't need to register or pay for 7-Zip.
|
|
||||||
|
|
||||||
|
|
||||||
GNU LGPL information
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You can receive a copy of the GNU Lesser General Public License from
|
|
||||||
http://www.gnu.org/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
BSD 3-clause License
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
The "BSD 3-clause License" is used for the code in 7z.dll that implements LZFSE data decompression.
|
|
||||||
That code was derived from the code in the "LZFSE compression library" developed by Apple Inc,
|
|
||||||
that also uses the "BSD 3-clause License":
|
|
||||||
|
|
||||||
----
|
|
||||||
Copyright (c) 2015-2016, Apple Inc. All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
|
||||||
|
|
||||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
|
||||||
|
|
||||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
|
|
||||||
in the documentation and/or other materials provided with the distribution.
|
|
||||||
|
|
||||||
3. Neither the name of the copyright holder(s) nor the names of any contributors may be used to endorse or promote products derived
|
|
||||||
from this software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
||||||
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
||||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
----
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
unRAR license restriction
|
|
||||||
-------------------------
|
|
||||||
|
|
||||||
The decompression engine for RAR archives was developed using source
|
|
||||||
code of unRAR program.
|
|
||||||
All copyrights to original unRAR code are owned by Alexander Roshal.
|
|
||||||
|
|
||||||
The license for original unRAR code has the following restriction:
|
|
||||||
|
|
||||||
The unRAR sources cannot be used to re-create the RAR compression algorithm,
|
|
||||||
which is proprietary. Distribution of modified unRAR sources in separate form
|
|
||||||
or as a part of other software is permitted, provided that it is clearly
|
|
||||||
stated in the documentation and source comments that the code may
|
|
||||||
not be used to develop a RAR (WinRAR) compatible archiver.
|
|
||||||
|
|
||||||
|
|
||||||
--
|
|
||||||
Igor Pavlov
|
|
||||||
@@ -1,233 +0,0 @@
|
|||||||
{\rtf1\adeflang1025\ansi\ansicpg1250\uc1\adeff0\deff0\stshfdbch0\stshfloch31506\stshfhich31506\stshfbi31506\deflang1045\deflangfe1045\themelang1045\themelangfe0\themelangcs0{\fonttbl{\f0\fbidi \froman\fcharset238\fprq2{\*\panose 02020603050405020304}Times New Roman;}
|
|
||||||
{\f0\fbidi \froman\fcharset238\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f37\fbidi \fswiss\fcharset238\fprq2{\*\panose 020f0502020204030204}Calibri;}
|
|
||||||
{\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;}
|
|
||||||
{\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;}{\f44\fbidi \froman\fcharset0\fprq2 Times New Roman;}
|
|
||||||
{\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);}
|
|
||||||
{\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;}
|
|
||||||
{\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);}
|
|
||||||
{\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;}
|
|
||||||
{\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);}
|
|
||||||
{\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\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\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;}
|
|
||||||
{\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\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\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\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;}
|
|
||||||
{\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\f31546\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\flominor\f31550\fbidi \froman\fcharset0\fprq2 Times New Roman;}{\flominor\f31549\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}
|
|
||||||
{\flominor\f31551\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\flominor\f31552\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\flominor\f31553\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}
|
|
||||||
{\flominor\f31554\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\flominor\f31555\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\flominor\f31556\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}
|
|
||||||
{\fdbminor\f31560\fbidi \froman\fcharset0\fprq2 Times New Roman;}{\fdbminor\f31559\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\fdbminor\f31561\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}
|
|
||||||
{\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;}
|
|
||||||
{\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\f31573\fbidi \fswiss\fcharset177\fprq2 Calibri (Hebrew);}{\fhiminor\f31574\fbidi \fswiss\fcharset178\fprq2 Calibri (Arabic);}{\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;}{\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;}{\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\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;\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;\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\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\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
|
|
||||||
\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
|
|
||||||
\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\yr2017\mo8\dy20\hr17\min40}{\version9}{\edmins8}{\nofpages1}{\nofwords33}{\nofchars201}{\nofcharsws233}{\vern39}}{\*\xmlnstbl {\xmlns1 http:
|
|
||||||
//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
|
|
||||||
\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
|
|
||||||
\asianbrkrule\rsidroot11107340\newtblstyruls\nogrowautofit\usenormstyforlist\noindnmbrts\felnbrelev\nocxsptable\indrlsweleven\noafcnsttbl\afelev\utinl\hwelev\spltpgpar\notcvasp\notbrkcnstfrctbl\notvatxbx\krnprsnet\cachedcolbal \nouicompat \fet0
|
|
||||||
{\*\wgrffmtfilter 2450}\nofeaturethrottle1\ilfomacatclnup0\ltrpar \sectd \ltrsect\linex0\headery708\footery708\colsx708\endnhere\sectlinegrid360\sectdefaultcl\sftnbj {\*\pnseclvl1\pnucrm\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl2
|
|
||||||
\pnucltr\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl3\pndec\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl4\pnlcltr\pnstart1\pnindent720\pnhang {\pntxta )}}{\*\pnseclvl5\pndec\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl6
|
|
||||||
\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl7\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl8\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl9\pnlcrm\pnstart1\pnindent720\pnhang
|
|
||||||
{\pntxtb (}{\pntxta )}}\pard\plain \ltrpar\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\cgrid\langnp1045\langfenp1033 {\rtlch\fcs1 \af0 \ltrch\fcs0 \b\fs52\cf6\lang2057\langfe1033\langnp2057\insrsid3562894\charrsid3562894 Warning!}{\rtlch\fcs1 \af0 \ltrch\fcs0
|
|
||||||
\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
|
|
||||||
\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}{\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
|
|
||||||
\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
|
|
||||||
00d0c9ea79f9bace118c8200aa004ba90b0200000003000000e0c9ea79f9bace118c8200aa004ba90b9600000068007400740070003a002f002f007700770077002e0061006d0061007a006f006e002e0063006f006d002f00670070002f0066006500610074007500720065002e00680074006d006c003f00690065003d00
|
|
||||||
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
|
|
||||||
\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
|
|
||||||
\af0\afs24 \ltrch\fcs0 \fs28\lang2057\langfe1033\langnp2057\insrsid5731975\charrsid12600926 }{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0 \fs28\lang2057\langfe1033\langnp2057\insrsid3562894\charrsid12600926 inside }{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0
|
|
||||||
\b\fs28\lang2057\langfe1033\langnp2057\insrsid3146412\charrsid3146412 Kindle}{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0 \b\fs28\lang2057\langfe1033\langnp2057\insrsid3146412 }{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0
|
|
||||||
\b\fs28\lang2057\langfe1033\langnp2057\insrsid3146412\charrsid3146412 Comic}{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0 \b\fs28\lang2057\langfe1033\langnp2057\insrsid3146412 }{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0
|
|
||||||
\b\fs28\lang2057\langfe1033\langnp2057\insrsid3146412\charrsid3146412 Converter}{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0 \b\fs28\lang2057\langfe1033\langnp2057\insrsid3146412 }{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0
|
|
||||||
\fs28\lang2057\langfe1033\langnp2057\insrsid3562894\charrsid12600926 directory.
|
|
||||||
\par }{\*\themedata 504b030414000600080000002100e9de0fbfff0000001c020000130000005b436f6e74656e745f54797065735d2e786d6cac91cb4ec3301045f748fc83e52d4a
|
|
||||||
9cb2400825e982c78ec7a27cc0c8992416c9d8b2a755fbf74cd25442a820166c2cd933f79e3be372bd1f07b5c3989ca74aaff2422b24eb1b475da5df374fd9ad
|
|
||||||
5689811a183c61a50f98f4babebc2837878049899a52a57be670674cb23d8e90721f90a4d2fa3802cb35762680fd800ecd7551dc18eb899138e3c943d7e503b6
|
|
||||||
b01d583deee5f99824e290b4ba3f364eac4a430883b3c092d4eca8f946c916422ecab927f52ea42b89a1cd59c254f919b0e85e6535d135a8de20f20b8c12c3b0
|
|
||||||
0c895fcf6720192de6bf3b9e89ecdbd6596cbcdd8eb28e7c365ecc4ec1ff1460f53fe813d3cc7f5b7f020000ffff0300504b030414000600080000002100a5d6
|
|
||||||
a7e7c0000000360100000b0000005f72656c732f2e72656c73848fcf6ac3300c87ef85bd83d17d51d2c31825762fa590432fa37d00e1287f68221bdb1bebdb4f
|
|
||||||
c7060abb0884a4eff7a93dfeae8bf9e194e720169aaa06c3e2433fcb68e1763dbf7f82c985a4a725085b787086a37bdbb55fbc50d1a33ccd311ba548b6309512
|
|
||||||
0f88d94fbc52ae4264d1c910d24a45db3462247fa791715fd71f989e19e0364cd3f51652d73760ae8fa8c9ffb3c330cc9e4fc17faf2ce545046e37944c69e462
|
|
||||||
a1a82fe353bd90a865aad41ed0b5b8f9d6fd010000ffff0300504b0304140006000800000021006b799616830000008a0000001c0000007468656d652f746865
|
|
||||||
6d652f7468656d654d616e616765722e786d6c0ccc4d0ac3201040e17da17790d93763bb284562b2cbaebbf600439c1a41c7a0d29fdbd7e5e38337cedf14d59b
|
|
||||||
4b0d592c9c070d8a65cd2e88b7f07c2ca71ba8da481cc52c6ce1c715e6e97818c9b48d13df49c873517d23d59085adb5dd20d6b52bd521ef2cdd5eb9246a3d8b
|
|
||||||
4757e8d3f729e245eb2b260a0238fd010000ffff0300504b030414000600080000002100b7e72e45da060000a81a0000160000007468656d652f7468656d652f
|
|
||||||
7468656d65312e786d6cec595d8b1b37147d2ff43f0cf3eef86bc61f4bbcc11edbd936bbc9123b2979d4dab24759cdc88ce4dd981028c963a1509a963e34d0b7
|
|
||||||
3e94b68104fa92fe9a6d53da14f2177aa5198f255bdb4d96149692352c63f9dcaba37bef9cab195dbe722fa2ce114e386171cb2d5f2ab90e8e476c4ce269cbbd
|
|
||||||
35ec171aaec3058ac788b218b7dc05e6ee95ed0f3fb88cb6448823ec807dccb750cb0d85986d158b7c04c3885f62331cc36f13964448c0d7645a1c27e818fc46
|
|
||||||
b45829956ac50891d875621481db3d2616c7ce0c1d122ce6ce8dc9848cb0bbbd9ca44761a658703930a2c9404e8133cb7d65a39b8c0fcb12c8173ca089738468
|
|
||||||
cb8569c7ec7888ef09d7a1880bf8a1e596d49f5bdcbe5c445b991115a7d86a767df597d96506e3c38a9a33991ee4937a9eefd5dab97f05a06213d7abf76abd5a
|
|
||||||
ee4f01d068040b4eb9e83efd4eb3d3f533ac064a2f2dbebbf56eb56ce035ffd50dce6d5f7e0cbc02a5febd0d7cbf1f40140dbc02a5787f03ef79f54ae0197805
|
|
||||||
4af1b50d7cbdd4ee7a7503af402125f1e106bae4d7aac172b53964c2e88e15def4bd7ebd92395fa1a01af22293534c582cce28b908dd65491f70124f9120b123
|
|
||||||
16333c4123a8ed005172901067974c43a8bf198a1987e152a5d42f55e1bffc78ea4a05066d61a4594b7a40886f0c495a0e1f2564265aeec7e0d5d520af5ffcf8
|
|
||||||
fac533e7e4e1f39387bf9c3c7a74f2f0e7d49161b583e2a96ef5eafb2ffe7ef2a9f3d7b3ef5e3dfeca8ee73afef79f3efbedd72fed4058e92a042fbf7efac7f3
|
|
||||||
a72fbff9fccf1f1e5be0ed041de8f021893077aee363e7268b60612a0426737c90bc9dc5304444b768c7538e622467b1f8ef89d0405f5f208a2cb80e3623783b
|
|
||||||
01a5b101afceef1a8407613217c4e2f15a1819c03dc6688725d6285c937369611ecee3a97df264aee36e2274649b3b40b191dfde7c064a4b6c2e83101b34f729
|
|
||||||
8a059ae2180b47fec60e31b6acee0e21465cf7c828619c4d847387381d44ac21199203a39a56463b2482bc2c6c0421df466cf66e3b1d466dabeee22313097705
|
|
||||||
a216f2434c8d305e457381229bcb218aa81ef05d24421bc9c12219e9b81e1790e929a6cce98d31e7369b1b09ac574bfa3590177bdaf7e8223291892087369fbb
|
|
||||||
88311dd965874188a2990d3b2071a8633fe28750a2c8d967c206df63e61d22bf431e507c6aba6fc31e409fe06c35b805caaa5bac0a44fe324f2cb9bc8a9951bf
|
|
||||||
83059d20aca406f4dfd0f388c4678afb9aacfbffadac8390befcf68965551755d0db09b1de513b6b327e1a6e5dbc03968cc9c5d7ee2e9ac7fb186e97cd06f65e
|
|
||||||
badf4bb7fbbf97eed3eee7772fd82b8d06f9965bc574c7aef6efd159dbf709a174201614ef72b583e7d0a0c67d1894e6ea8116e74f75b3102ee50d0df318b869
|
|
||||||
82948d9330f10911e1204433d8e6975de964ca33d753eecc1887ddbf1ab6fa96783a8ff6d8387d782d97e5836aaa211c89d578c9cfc7e18943a4e85a7df54096
|
|
||||||
bb576ca7eaf9794940dabe0d096d329344d542a2be1c9441524feb10340b09b5b277c2a26961d190ee97a9da6001d4f2acc00eca817d57cbf53d30012378b042
|
|
||||||
148f659ed2542fb3ab92f92e337d5a308d0a80edc4b20256996e4aaea72e4fae2e2db537c8b441422b3793848a8c6a653c44639c55a71c7d131a6f9bebe62aa5
|
|
||||||
063d190a351f94d68a46bdf16f2cce9b6bb05bd7061aeb4a4163e7b8e5d6aa3e94cc08cd5aee049efee1329a41ed70b9f345740a2fd64622496ff8f328cb2ce1
|
|
||||||
a28b7898065c894eaa061111387128895aae5c7e9e061a2b0d51dcca1510840b4bae09b272d1c841d2cd24e3c9048f849e766d44463afd0a0a9f6a85f557657e
|
|
||||||
7eb0b4647348f7201c1f3b07749edc4450627ebd2c0338261c5e0295d3688e09bcdccc856c557f6b8d29935dfdeda2aaa1741cd15988b28ea28b790a57529ed3
|
|
||||||
51dff21868dfb2354340b590648df0602a1bac1e54a39be65d23e5706ad73ddb48464e13cd55cf345445764dbb8a19332cdbc05a2ccfd7e43556cb1083a6e91d
|
|
||||||
3e95ee75c96d2eb56e6d9f90770908781e3f4bd77d8386a0515b4d6650938c3765586a76366af68ee502cfa0f6264d4253fddad2ed5adcf21e619d0e06cfd5f9
|
|
||||||
c16ebd6a6168b2dc5eaa48ab4311fdbc821ddc05f1e8c2bbe039155ca5128e2112041ba281da93a4b201b7c83d91dd1a70e5cc13d272ef97fcb61754fca0506a
|
|
||||||
f8bd8257f54a8586dfae16dabe5f2df7fc72a9dba93c80c622c2a8eca707327d78234517d9b18c1adf389a89962fdd2e8d585464eab0a5a888aba39972c5389a
|
|
||||||
490f639ca13c73711d02a273bf56e937abcd4eadd0acb6fb05afdb69149a41ad53e8d6827ab7df0dfc46b3ffc0758e14d86b5703afd66b146ae5202878b592a4
|
|
||||||
df6816ea5ea5d2f6eaed46cf6b3fc8b631b0f2543eb258407815afed7f000000ffff0300504b0304140006000800000021000dd1909fb60000001b0100002700
|
|
||||||
00007468656d652f7468656d652f5f72656c732f7468656d654d616e616765722e786d6c2e72656c73848f4d0ac2301484f78277086f6fd3ba109126dd88d0ad
|
|
||||||
d40384e4350d363f2451eced0dae2c082e8761be9969bb979dc9136332de3168aa1a083ae995719ac16db8ec8e4052164e89d93b64b060828e6f37ed1567914b
|
|
||||||
284d262452282e3198720e274a939cd08a54f980ae38a38f56e422a3a641c8bbd048f7757da0f19b017cc524bd62107bd5001996509affb3fd381a89672f1f16
|
|
||||||
5dfe514173d9850528a2c6cce0239baa4c04ca5bbabac4df000000ffff0300504b01022d0014000600080000002100e9de0fbfff0000001c0200001300000000
|
|
||||||
000000000000000000000000005b436f6e74656e745f54797065735d2e786d6c504b01022d0014000600080000002100a5d6a7e7c0000000360100000b000000
|
|
||||||
00000000000000000000300100005f72656c732f2e72656c73504b01022d00140006000800000021006b799616830000008a0000001c00000000000000000000
|
|
||||||
000000190200007468656d652f7468656d652f7468656d654d616e616765722e786d6c504b01022d0014000600080000002100b7e72e45da060000a81a000016
|
|
||||||
00000000000000000000000000d60200007468656d652f7468656d652f7468656d65312e786d6c504b01022d00140006000800000021000dd1909fb60000001b
|
|
||||||
0100002700000000000000000000000000e40900007468656d652f7468656d652f5f72656c732f7468656d654d616e616765722e786d6c2e72656c73504b050600000000050005005d010000df0a00000000}
|
|
||||||
{\*\colorschememapping 3c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d225554462d3822207374616e64616c6f6e653d22796573223f3e0d0a3c613a636c724d
|
|
||||||
617020786d6c6e733a613d22687474703a2f2f736368656d61732e6f70656e786d6c666f726d6174732e6f72672f64726177696e676d6c2f323030362f6d6169
|
|
||||||
6e22206267313d226c743122207478313d22646b3122206267323d226c743222207478323d22646b322220616363656e74313d22616363656e74312220616363
|
|
||||||
656e74323d22616363656e74322220616363656e74333d22616363656e74332220616363656e74343d22616363656e74342220616363656e74353d22616363656e74352220616363656e74363d22616363656e74362220686c696e6b3d22686c696e6b2220666f6c486c696e6b3d22666f6c486c696e6b222f3e}
|
|
||||||
{\*\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 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 \lsdlocked0 index 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 4;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 5;
|
|
||||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 6;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 7;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 8;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 9;
|
|
||||||
\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 1;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 2;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 3;
|
|
||||||
\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 4;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 5;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 6;
|
|
||||||
\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 7;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 8;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 9;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Normal Indent;
|
|
||||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 footnote text;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 annotation text;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 header;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 footer;
|
|
||||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index heading;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority35 \lsdlocked0 caption;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 table of figures;
|
|
||||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 envelope address;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 envelope return;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 footnote reference;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 annotation reference;
|
|
||||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 line number;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 page number;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 endnote reference;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 endnote text;
|
|
||||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 table of authorities;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 macro;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 toa heading;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List;
|
|
||||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Bullet;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Number;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List 3;
|
|
||||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List 4;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List 5;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Bullet 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Bullet 3;
|
|
||||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Bullet 4;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Bullet 5;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Number 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Number 3;
|
|
||||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Number 4;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Number 5;\lsdqformat1 \lsdpriority10 \lsdlocked0 Title;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Closing;
|
|
||||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Signature;\lsdsemihidden1 \lsdunhideused1 \lsdpriority1 \lsdlocked0 Default Paragraph Font;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text Indent;
|
|
||||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Continue;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Continue 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Continue 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Continue 4;
|
|
||||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Continue 5;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Message Header;\lsdqformat1 \lsdpriority11 \lsdlocked0 Subtitle;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Salutation;
|
|
||||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Date;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text First Indent;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text First Indent 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Note Heading;
|
|
||||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text Indent 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text Indent 3;
|
|
||||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Block Text;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Hyperlink;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 FollowedHyperlink;\lsdqformat1 \lsdpriority22 \lsdlocked0 Strong;
|
|
||||||
\lsdqformat1 \lsdpriority20 \lsdlocked0 Emphasis;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Document Map;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Plain Text;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 E-mail Signature;
|
|
||||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Top of Form;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Bottom of Form;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Normal (Web);\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Acronym;
|
|
||||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Address;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Cite;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Code;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Definition;
|
|
||||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Keyboard;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Preformatted;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Sample;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Typewriter;
|
|
||||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Variable;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 annotation subject;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 No List;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Outline List 1;
|
|
||||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Outline List 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Outline List 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Balloon Text;\lsdpriority39 \lsdlocked0 Table Grid;
|
|
||||||
\lsdsemihidden1 \lsdlocked0 Placeholder Text;\lsdqformat1 \lsdpriority1 \lsdlocked0 No Spacing;\lsdpriority60 \lsdlocked0 Light Shading;\lsdpriority61 \lsdlocked0 Light List;\lsdpriority62 \lsdlocked0 Light Grid;
|
|
||||||
\lsdpriority63 \lsdlocked0 Medium Shading 1;\lsdpriority64 \lsdlocked0 Medium Shading 2;\lsdpriority65 \lsdlocked0 Medium List 1;\lsdpriority66 \lsdlocked0 Medium List 2;\lsdpriority67 \lsdlocked0 Medium Grid 1;\lsdpriority68 \lsdlocked0 Medium Grid 2;
|
|
||||||
\lsdpriority69 \lsdlocked0 Medium Grid 3;\lsdpriority70 \lsdlocked0 Dark List;\lsdpriority71 \lsdlocked0 Colorful Shading;\lsdpriority72 \lsdlocked0 Colorful List;\lsdpriority73 \lsdlocked0 Colorful Grid;\lsdpriority60 \lsdlocked0 Light Shading Accent 1;
|
|
||||||
\lsdpriority61 \lsdlocked0 Light List Accent 1;\lsdpriority62 \lsdlocked0 Light Grid Accent 1;\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 1;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 1;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 1;
|
|
||||||
\lsdsemihidden1 \lsdlocked0 Revision;\lsdqformat1 \lsdpriority34 \lsdlocked0 List Paragraph;\lsdqformat1 \lsdpriority29 \lsdlocked0 Quote;\lsdqformat1 \lsdpriority30 \lsdlocked0 Intense Quote;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 1;
|
|
||||||
\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 1;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 1;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 1;\lsdpriority70 \lsdlocked0 Dark List Accent 1;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 1;
|
|
||||||
\lsdpriority72 \lsdlocked0 Colorful List Accent 1;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 1;\lsdpriority60 \lsdlocked0 Light Shading Accent 2;\lsdpriority61 \lsdlocked0 Light List Accent 2;\lsdpriority62 \lsdlocked0 Light Grid Accent 2;
|
|
||||||
\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 2;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 2;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 2;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 2;
|
|
||||||
\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 2;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 2;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 2;\lsdpriority70 \lsdlocked0 Dark List Accent 2;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 2;
|
|
||||||
\lsdpriority72 \lsdlocked0 Colorful List Accent 2;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 2;\lsdpriority60 \lsdlocked0 Light Shading Accent 3;\lsdpriority61 \lsdlocked0 Light List Accent 3;\lsdpriority62 \lsdlocked0 Light Grid Accent 3;
|
|
||||||
\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 3;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 3;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 3;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 3;
|
|
||||||
\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 3;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 3;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 3;\lsdpriority70 \lsdlocked0 Dark List Accent 3;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 3;
|
|
||||||
\lsdpriority72 \lsdlocked0 Colorful List Accent 3;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 3;\lsdpriority60 \lsdlocked0 Light Shading Accent 4;\lsdpriority61 \lsdlocked0 Light List Accent 4;\lsdpriority62 \lsdlocked0 Light Grid Accent 4;
|
|
||||||
\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 4;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 4;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 4;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 4;
|
|
||||||
\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 4;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 4;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 4;\lsdpriority70 \lsdlocked0 Dark List Accent 4;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 4;
|
|
||||||
\lsdpriority72 \lsdlocked0 Colorful List Accent 4;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 4;\lsdpriority60 \lsdlocked0 Light Shading Accent 5;\lsdpriority61 \lsdlocked0 Light List Accent 5;\lsdpriority62 \lsdlocked0 Light Grid Accent 5;
|
|
||||||
\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 5;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 5;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 5;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 5;
|
|
||||||
\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 5;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 5;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 5;\lsdpriority70 \lsdlocked0 Dark List Accent 5;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 5;
|
|
||||||
\lsdpriority72 \lsdlocked0 Colorful List Accent 5;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 5;\lsdpriority60 \lsdlocked0 Light Shading Accent 6;\lsdpriority61 \lsdlocked0 Light List Accent 6;\lsdpriority62 \lsdlocked0 Light Grid Accent 6;
|
|
||||||
\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 6;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 6;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 6;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 6;
|
|
||||||
\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 6;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 6;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 6;\lsdpriority70 \lsdlocked0 Dark List Accent 6;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 6;
|
|
||||||
\lsdpriority72 \lsdlocked0 Colorful List Accent 6;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 6;\lsdqformat1 \lsdpriority19 \lsdlocked0 Subtle Emphasis;\lsdqformat1 \lsdpriority21 \lsdlocked0 Intense Emphasis;
|
|
||||||
\lsdqformat1 \lsdpriority31 \lsdlocked0 Subtle Reference;\lsdqformat1 \lsdpriority32 \lsdlocked0 Intense Reference;\lsdqformat1 \lsdpriority33 \lsdlocked0 Book Title;\lsdsemihidden1 \lsdunhideused1 \lsdpriority37 \lsdlocked0 Bibliography;
|
|
||||||
\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority39 \lsdlocked0 TOC Heading;\lsdpriority41 \lsdlocked0 Plain Table 1;\lsdpriority42 \lsdlocked0 Plain Table 2;\lsdpriority43 \lsdlocked0 Plain Table 3;\lsdpriority44 \lsdlocked0 Plain Table 4;
|
|
||||||
\lsdpriority45 \lsdlocked0 Plain Table 5;\lsdpriority40 \lsdlocked0 Grid Table Light;\lsdpriority46 \lsdlocked0 Grid Table 1 Light;\lsdpriority47 \lsdlocked0 Grid Table 2;\lsdpriority48 \lsdlocked0 Grid Table 3;\lsdpriority49 \lsdlocked0 Grid Table 4;
|
|
||||||
\lsdpriority50 \lsdlocked0 Grid Table 5 Dark;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 1;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 1;
|
|
||||||
\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 1;\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 1;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 1;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 1;
|
|
||||||
\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 1;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 2;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 2;\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 2;
|
|
||||||
\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 2;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 2;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 2;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 2;
|
|
||||||
\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 3;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 3;\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 3;\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 3;
|
|
||||||
\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 3;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 3;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 3;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 4;
|
|
||||||
\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 4;\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 4;\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 4;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 4;
|
|
||||||
\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 4;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 4;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 5;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 5;
|
|
||||||
\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 5;\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 5;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 5;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 5;
|
|
||||||
\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 5;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 6;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 6;\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 6;
|
|
||||||
\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 6;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 6;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 6;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 6;
|
|
||||||
\lsdpriority46 \lsdlocked0 List Table 1 Light;\lsdpriority47 \lsdlocked0 List Table 2;\lsdpriority48 \lsdlocked0 List Table 3;\lsdpriority49 \lsdlocked0 List Table 4;\lsdpriority50 \lsdlocked0 List Table 5 Dark;
|
|
||||||
\lsdpriority51 \lsdlocked0 List Table 6 Colorful;\lsdpriority52 \lsdlocked0 List Table 7 Colorful;\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 1;\lsdpriority47 \lsdlocked0 List Table 2 Accent 1;\lsdpriority48 \lsdlocked0 List Table 3 Accent 1;
|
|
||||||
\lsdpriority49 \lsdlocked0 List Table 4 Accent 1;\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 1;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 1;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 1;
|
|
||||||
\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 2;\lsdpriority47 \lsdlocked0 List Table 2 Accent 2;\lsdpriority48 \lsdlocked0 List Table 3 Accent 2;\lsdpriority49 \lsdlocked0 List Table 4 Accent 2;
|
|
||||||
\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 2;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 2;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 2;\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 3;
|
|
||||||
\lsdpriority47 \lsdlocked0 List Table 2 Accent 3;\lsdpriority48 \lsdlocked0 List Table 3 Accent 3;\lsdpriority49 \lsdlocked0 List Table 4 Accent 3;\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 3;
|
|
||||||
\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 3;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 3;\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 4;\lsdpriority47 \lsdlocked0 List Table 2 Accent 4;
|
|
||||||
\lsdpriority48 \lsdlocked0 List Table 3 Accent 4;\lsdpriority49 \lsdlocked0 List Table 4 Accent 4;\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 4;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 4;
|
|
||||||
\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;
|
|
||||||
\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;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Mention;
|
|
||||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Smart Hyperlink;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Hashtag;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Unresolved Mention;}}{\*\datastore 010500000200000018000000
|
|
||||||
4d73786d6c322e534158584d4c5265616465722e362e30000000000000000000000e0000
|
|
||||||
d0cf11e0a1b11ae1000000000000000000000000000000003e000300feff0900060000000000000000000000010000000100000000000000001000000200000001000000feffffff0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
|
||||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
|
||||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
|
||||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
|
||||||
fffffffffffffffffdffffff04000000feffffff05000000fefffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
|
||||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
|
||||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
|
||||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
|
||||||
ffffffffffffffffffffffffffffffff52006f006f007400200045006e00740072007900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000500ffffffffffffffff010000000c6ad98892f1d411a65f0040963251e5000000000000000000000000b00f
|
|
||||||
9da8ca19d30103000000c0020000000000004d0073006f004400610074006100530074006f0072006500000000000000000000000000000000000000000000000000000000000000000000000000000000001a000101ffffffffffffffff020000000000000000000000000000000000000000000000b00f9da8ca19d301
|
|
||||||
b00f9da8ca19d301000000000000000000000000ca0041004300c300d300d300c70058004d00d4003000c9004d00c200590043003100320055004a00300051003d003d000000000000000000000000000000000032000101ffffffffffffffff030000000000000000000000000000000000000000000000b00f9da8ca19
|
|
||||||
d301b00f9da8ca19d3010000000000000000000000004900740065006d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000201ffffffff04000000ffffffff000000000000000000000000000000000000000000000000
|
|
||||||
00000000000000000000000000000000320100000000000001000000020000000300000004000000feffffff060000000700000008000000090000000a000000feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
|
||||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
|
||||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
|
||||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
|
||||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d225554462d3822207374616e64616c6f6e653d226e6f223f3e3c623a536f75726365732053656c65637465645374796c653d225c41504153697874684564697469
|
|
||||||
6f6e4f66666963654f6e6c696e652e78736c22205374796c654e616d653d22415041222056657273696f6e3d22362220786d6c6e733a623d22687474703a2f2f736368656d61732e6f70656e786d6c666f726d6174732e6f72672f6f6666696365446f63756d656e742f323030362f6269626c696f677261706879222078
|
|
||||||
6d6c6e733d22687474703a2f2f736368656d61732e6f70656e786d6c666f726d6174732e6f72672f6f6666696365446f63756d656e742f323030362f6269626c696f677261706879223e3c2f623a536f75726365733e00000000000000000000000000003c3f786d6c2076657273696f6e3d22312e302220656e636f6469
|
|
||||||
6e673d225554462d3822207374616e64616c6f6e653d226e6f223f3e0d0a3c64733a6461746173746f72654974656d2064733a6974656d49443d227b43464133303041382d443733392d343633332d413933322d3236303236444335303936397d2220786d6c6e733a64733d22687474703a2f2f736368656d61732e6f70
|
|
||||||
656e786d6c666f726d6174732e6f72672f6f6666696365446f63756d656e742f323030362f637573500072006f007000650072007400690065007300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000200ffffffffffffffffffffffff000000000000
|
|
||||||
0000000000000000000000000000000000000000000000000000000000000500000055010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff00000000
|
|
||||||
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff0000
|
|
||||||
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff
|
|
||||||
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000746f6d586d6c223e3c64733a736368656d61526566733e3c64733a736368656d615265662064733a7572693d22687474703a2f2f736368656d61732e6f70656e786d6c666f726d6174732e6f7267
|
|
||||||
2f6f6666696365446f63756d656e742f323030362f6269626c696f677261706879222f3e3c2f64733a736368656d61526566733e3c2f64733a6461746173746f72654974656d3e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
|
||||||
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
|
||||||
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
|
||||||
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000105000000000000}}
|
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
PyQt5>=5.6.0
|
PyQt5>=5.6.0
|
||||||
Pillow>=5.2.0
|
Pillow>=5.2.0
|
||||||
psutil>=5.0.0
|
psutil>=5.0.0
|
||||||
python-slugify>=1.2.1,<8.0.0
|
python-slugify>=1.2.1
|
||||||
raven>=6.0.0
|
raven>=6.0.0
|
||||||
# PyQt5-tools
|
# PyQt5-tools
|
||||||
mozjpeg-lossless-optimization
|
mozjpeg-lossless-optimization>=1.1.2
|
||||||
|
distro
|
||||||
|
|||||||
21
setup.py
21
setup.py
@@ -17,8 +17,6 @@ import setuptools
|
|||||||
import distutils.cmd
|
import distutils.cmd
|
||||||
from kindlecomicconverter import __version__
|
from kindlecomicconverter import __version__
|
||||||
|
|
||||||
OSX_INFO_PLIST = "other/osx/Info.plist"
|
|
||||||
|
|
||||||
NAME = 'KindleComicConverter'
|
NAME = 'KindleComicConverter'
|
||||||
MAIN = 'kcc.py'
|
MAIN = 'kcc.py'
|
||||||
VERSION = __version__
|
VERSION = __version__
|
||||||
@@ -39,22 +37,8 @@ class BuildBinaryCommand(distutils.cmd.Command):
|
|||||||
def run(self):
|
def run(self):
|
||||||
VERSION = __version__
|
VERSION = __version__
|
||||||
if sys.platform == 'darwin':
|
if sys.platform == 'darwin':
|
||||||
|
|
||||||
with open(OSX_INFO_PLIST, 'r') as file:
|
|
||||||
filedata = file.read()
|
|
||||||
filedata = filedata.replace('5.5.2', VERSION)
|
|
||||||
with open(OSX_INFO_PLIST, 'w') as file:
|
|
||||||
file.write(filedata)
|
|
||||||
|
|
||||||
os.system('pyinstaller -y -F -i icons/comic2ebook.icns -n "Kindle Comic Converter" -w -s kcc.py')
|
os.system('pyinstaller -y -F -i icons/comic2ebook.icns -n "Kindle Comic Converter" -w -s kcc.py')
|
||||||
os.makedirs('dist/Kindle Comic Converter.app/Contents/Resources/Codecs')
|
# TODO /usr/bin/codesign --force -s "$MACOS_CERTIFICATE_NAME" --options runtime dist/Applications/Kindle\ Comic\ Converter.app -v
|
||||||
shutil.copy('other/osx/7z', 'dist/Kindle Comic Converter.app/Contents/Resources')
|
|
||||||
shutil.copy('other/osx/7z.so', 'dist/Kindle Comic Converter.app/Contents/Resources')
|
|
||||||
shutil.copy('other/osx/Rar.so', 'dist/Kindle Comic Converter.app/Contents/Resources/Codecs')
|
|
||||||
shutil.copy('other/osx/Info.plist', 'dist/Kindle Comic Converter.app/Contents')
|
|
||||||
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)
|
|
||||||
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':
|
||||||
@@ -94,8 +78,9 @@ setuptools.setup(
|
|||||||
'PyQt5>=5.6.0',
|
'PyQt5>=5.6.0',
|
||||||
'Pillow>=5.2.0',
|
'Pillow>=5.2.0',
|
||||||
'psutil>=5.0.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',
|
'raven>=6.0.0',
|
||||||
|
'mozjpeg-lossless-optimization>=1.1.2',
|
||||||
],
|
],
|
||||||
classifiers=[],
|
classifiers=[],
|
||||||
zip_safe=False,
|
zip_safe=False,
|
||||||
|
|||||||
Reference in New Issue
Block a user