mirror of
https://github.com/ciromattia/kcc
synced 2026-04-18 06:58:58 +00:00
Compare commits
110 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a822dfa3ae | ||
|
|
70de379987 | ||
|
|
16e275bb1f | ||
|
|
b225de7b97 | ||
|
|
4a89446914 | ||
|
|
64521de577 | ||
|
|
38b14fd734 | ||
|
|
4fa72780a1 | ||
|
|
c979486e28 | ||
|
|
03bd67cf2f | ||
|
|
b44af66484 | ||
|
|
754395f1b3 | ||
|
|
95e73ea1dd | ||
|
|
f466701b5d | ||
|
|
bc6b26862f | ||
|
|
b4d86fed7f | ||
|
|
b5806ece0e | ||
|
|
85a99f0b05 | ||
|
|
4fea796763 | ||
|
|
ca8bdf7e1f | ||
|
|
33d57d5025 | ||
|
|
cceb9cf61f | ||
|
|
9ee375c6e4 | ||
|
|
a50345a26d | ||
|
|
be4b35b705 | ||
|
|
608e79a9fc | ||
|
|
7468512ec8 | ||
|
|
2256df0785 | ||
|
|
378a3caccc | ||
|
|
ab7d629ba9 | ||
|
|
b54299ff76 | ||
|
|
1d3fc9cc92 | ||
|
|
49313ce030 | ||
|
|
c0d17c1803 | ||
|
|
7f883f98ba | ||
|
|
2c19898952 | ||
|
|
12c663bc05 | ||
|
|
d8957dc4a6 | ||
|
|
9b45633279 | ||
|
|
b5a0126051 | ||
|
|
182a292f70 | ||
|
|
7ab96c5573 | ||
|
|
1fbfaeae01 | ||
|
|
2462d11b5e | ||
|
|
44e6ffe4e3 | ||
|
|
9be2a4a492 | ||
|
|
3ea9a486bf | ||
|
|
95f138887e | ||
|
|
a7a01f8269 | ||
|
|
6987c8b1cd | ||
|
|
6e10636356 | ||
|
|
63bd55313f | ||
|
|
324047bebc | ||
|
|
842a729c75 | ||
|
|
27d3eab8d5 | ||
|
|
8035dedae8 | ||
|
|
b39076a9f4 | ||
|
|
237f343e62 | ||
|
|
ab60d67ab7 | ||
|
|
79715c6a06 | ||
|
|
6cd073809e | ||
|
|
9dac000a04 | ||
|
|
674121620f | ||
|
|
f6e2ceae91 | ||
|
|
143f6eb0f9 | ||
|
|
7cac6d4008 | ||
|
|
aa4456bdb1 | ||
|
|
c91be77588 | ||
|
|
65a42c1063 | ||
|
|
6519eb0453 | ||
|
|
9fdbf095d3 | ||
|
|
4ec4c9966c | ||
|
|
5a51c5234e | ||
|
|
b7c6fd30e4 | ||
|
|
515b83637f | ||
|
|
c3dad087d3 | ||
|
|
67e913ed9e | ||
|
|
6ce0f76fe0 | ||
|
|
5f5157c1d4 | ||
|
|
4c13ef0f6c | ||
|
|
50dc7fbffe | ||
|
|
a060498ac7 | ||
|
|
35bba68a72 | ||
|
|
0b056a8fa8 | ||
|
|
a6f9e84251 | ||
|
|
259800e48b | ||
|
|
28e170f1d2 | ||
|
|
7120c76025 | ||
|
|
4891913b5c | ||
|
|
cd83b2899c | ||
|
|
535c2c220b | ||
|
|
409f077c3e | ||
|
|
3ecb2ba877 | ||
|
|
c07a9657ef | ||
|
|
7f719a22ad | ||
|
|
332d3d455e | ||
|
|
2070a977ae | ||
|
|
8f8d0d68a3 | ||
|
|
5a8deb4623 | ||
|
|
a7ea795df5 | ||
|
|
a2ffd259b8 | ||
|
|
93e6b51466 | ||
|
|
7904662f25 | ||
|
|
6792c2d366 | ||
|
|
ef4a91e44d | ||
|
|
a2a405e5f5 | ||
|
|
a63a46a741 | ||
|
|
2591b53a09 | ||
|
|
1c615ffc20 | ||
|
|
6eb05b3a8f |
14
.dockerignore
Normal file
14
.dockerignore
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
.git
|
||||||
|
.github
|
||||||
|
build
|
||||||
|
dist
|
||||||
|
KindleComicConverter.egg-info
|
||||||
|
.dockerignore
|
||||||
|
.gitignore
|
||||||
|
.travis.yml
|
||||||
|
Dockerfile
|
||||||
|
other
|
||||||
|
venv
|
||||||
|
*.md
|
||||||
|
LICENSE.txt
|
||||||
|
MANIFEST.in
|
||||||
25
.github/dependabot.yml
vendored
Normal file
25
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
# To get started with Dependabot version updates, you'll need to specify which
|
||||||
|
# package ecosystems to update and where the package manifests are located.
|
||||||
|
# Please see the documentation for all configuration options:
|
||||||
|
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
||||||
|
|
||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
- package-ecosystem: "pip"
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: "weekly"
|
||||||
|
|
||||||
|
# Enable version updates for Docker
|
||||||
|
- package-ecosystem: "docker"
|
||||||
|
# Look for a `Dockerfile` in the `root` directory
|
||||||
|
directory: "/"
|
||||||
|
# Check for updates once a week
|
||||||
|
schedule:
|
||||||
|
interval: "weekly"
|
||||||
|
|
||||||
|
# Maintain dependencies for GitHub Actions
|
||||||
|
- package-ecosystem: "github-actions"
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: "weekly"
|
||||||
74
.github/workflows/codeql-analysis.yml
vendored
Normal file
74
.github/workflows/codeql-analysis.yml
vendored
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
# For most projects, this workflow file will not need changing; you simply need
|
||||||
|
# to commit it to your repository.
|
||||||
|
#
|
||||||
|
# You may wish to alter this file to override the set of languages analyzed,
|
||||||
|
# or to provide custom queries or build logic.
|
||||||
|
#
|
||||||
|
# ******** NOTE ********
|
||||||
|
# We have attempted to detect the languages in your repository. Please check
|
||||||
|
# the `language` matrix defined below to confirm you have the correct set of
|
||||||
|
# supported CodeQL languages.
|
||||||
|
#
|
||||||
|
name: "CodeQL"
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "beta_release" ]
|
||||||
|
pull_request:
|
||||||
|
# The branches below must be a subset of the branches above
|
||||||
|
branches: [ "beta_release" ]
|
||||||
|
schedule:
|
||||||
|
- cron: '42 22 * * 3'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
analyze:
|
||||||
|
name: Analyze
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
actions: read
|
||||||
|
contents: read
|
||||||
|
security-events: write
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
language: [ 'python' ]
|
||||||
|
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
|
||||||
|
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
# Initializes the CodeQL tools for scanning.
|
||||||
|
- name: Initialize CodeQL
|
||||||
|
uses: github/codeql-action/init@v2
|
||||||
|
with:
|
||||||
|
languages: ${{ matrix.language }}
|
||||||
|
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||||
|
# By default, queries listed here will override any specified in a config file.
|
||||||
|
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||||
|
|
||||||
|
# Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
|
||||||
|
# queries: security-extended,security-and-quality
|
||||||
|
|
||||||
|
|
||||||
|
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||||
|
# If this step fails, then you should remove it and run the build manually (see below)
|
||||||
|
- name: Autobuild
|
||||||
|
uses: github/codeql-action/autobuild@v2
|
||||||
|
|
||||||
|
# ℹ️ Command-line programs to run using the OS shell.
|
||||||
|
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||||
|
|
||||||
|
# If the Autobuild fails above, remove it and uncomment the following three lines.
|
||||||
|
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
|
||||||
|
|
||||||
|
# - run: |
|
||||||
|
# echo "Run, Build Application using script"
|
||||||
|
# ./location_of_script_within_repo/buildscript.sh
|
||||||
|
|
||||||
|
- name: Perform CodeQL Analysis
|
||||||
|
uses: github/codeql-action/analyze@v2
|
||||||
|
with:
|
||||||
|
category: "/language:${{matrix.language}}"
|
||||||
36
.github/workflows/docker-publish.yml
vendored
Normal file
36
.github/workflows/docker-publish.yml
vendored
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
name: Docker
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
#schedule:
|
||||||
|
# - cron: '39 5 * * *'
|
||||||
|
push:
|
||||||
|
# branches: [ master, pipeline_test, docker_test ]
|
||||||
|
# Publish semver tags as releases.
|
||||||
|
tags: [ 'v*.*.*' ]
|
||||||
|
|
||||||
|
# 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:
|
||||||
|
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 }}
|
||||||
|
secrets:
|
||||||
|
ghcr_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
82
.github/workflows/package-linux.yml
vendored
Normal file
82
.github/workflows/package-linux.yml
vendored
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
|
||||||
|
|
||||||
|
name: build KCC for Linux
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
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:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-20.04
|
||||||
|
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: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y libpng-dev libjpeg-dev p7zip-full python3-pyqt5 squashfs-tools
|
||||||
|
python -m pip install --upgrade pip setuptools wheel pyinstaller
|
||||||
|
pip install -r requirements.txt
|
||||||
|
- name: build binary
|
||||||
|
run: |
|
||||||
|
python setup.py build_binary
|
||||||
|
chmod +x dist/kcc_linux*
|
||||||
|
- name: upload build
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: linux-build
|
||||||
|
path: dist/kcc_linux*
|
||||||
|
# issue with this action, disabled and commented out
|
||||||
|
# see https://github.com/AppImageCrafters/build-appimage/issues/5
|
||||||
|
# see https://appimage-builder.readthedocs.io/en/latest/intro/install.html#install-appimagetool
|
||||||
|
# - name: Build AppImage
|
||||||
|
# uses: AppImageCrafters/build-appimage-action@master
|
||||||
|
# env:
|
||||||
|
# UPDATE_INFO: gh-releases-zsync|ciromattia|kcc|latest|*x86_64.AppImage.zsync
|
||||||
|
# with:
|
||||||
|
# recipe: AppImageBuilder.yml
|
||||||
|
- name: Build AppImage
|
||||||
|
run: |
|
||||||
|
wget -O appimage-builder-x86_64.AppImage https://github.com/AppImageCrafters/appimage-builder/releases/download/v1.1.0/appimage-builder-1.1.0-x86_64.AppImage
|
||||||
|
chmod +x appimage-builder-x86_64.AppImage
|
||||||
|
sudo mv appimage-builder-x86_64.AppImage /usr/local/bin/appimage-builder
|
||||||
|
appimage-builder --recipe AppImageBuilder.yml --skip-test
|
||||||
|
env:
|
||||||
|
UPDATE_INFO: gh-releases-zsync|ciromattia|kcc|latest|*x86_64.AppImage.zsync
|
||||||
|
|
||||||
|
- name: upload artifact
|
||||||
|
uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: AppImage
|
||||||
|
path: './*.AppImage*'
|
||||||
|
- 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/kcc_linux*
|
||||||
|
*.AppImage*
|
||||||
59
.github/workflows/package-macos.yml
vendored
Normal file
59
.github/workflows/package-macos.yml
vendored
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
|
||||||
|
|
||||||
|
name: build KCC for mac os
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
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:
|
||||||
|
build:
|
||||||
|
runs-on: macos-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
|
||||||
|
- uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: 16
|
||||||
|
- run: npm install -g appdmg
|
||||||
|
- name: build binary
|
||||||
|
run: |
|
||||||
|
python setup.py build_binary
|
||||||
|
- name: upload build
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: mac-os-build
|
||||||
|
path: dist/*.dmg
|
||||||
|
- 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/*.dmg
|
||||||
55
.github/workflows/package-windows.yml
vendored
Normal file
55
.github/workflows/package-windows.yml
vendored
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
|
||||||
|
|
||||||
|
name: build KCC for windows
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
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:
|
||||||
|
build:
|
||||||
|
runs-on: windows-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 binary
|
||||||
|
run: |
|
||||||
|
python setup.py build_binary
|
||||||
|
- name: upload build
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: windows-build
|
||||||
|
path: dist/*.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/*.exe
|
||||||
50
.github/workflows/python-package-test.yml
vendored
Normal file
50
.github/workflows/python-package-test.yml
vendored
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
# 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
Normal file
44
.github/workflows/python-package.yml
vendored
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
# 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 }}
|
||||||
20
.gitignore
vendored
20
.gitignore
vendored
@@ -1,15 +1,13 @@
|
|||||||
*.pyc
|
*.pyc
|
||||||
*.cbz
|
Pipfile
|
||||||
*.cbr
|
Pipfile.lock
|
||||||
*.spec
|
|
||||||
.idea
|
|
||||||
.DS_Store
|
|
||||||
.python-version
|
|
||||||
Thumbs.db
|
|
||||||
dist
|
|
||||||
Output
|
|
||||||
kindlegen*
|
|
||||||
setup.bat
|
setup.bat
|
||||||
kindlecomicconverter/sentry.py
|
kindlecomicconverter/sentry.py
|
||||||
|
other/windows/kindlegen.exe
|
||||||
|
dist/
|
||||||
build/
|
build/
|
||||||
KindleComicConverter.egg-info/
|
KindleComicConverter*.egg-info/
|
||||||
|
.idea/
|
||||||
|
/venv/
|
||||||
|
/kindlegen*
|
||||||
|
/kcc.bat
|
||||||
|
|||||||
23
.travis.yml
23
.travis.yml
@@ -2,20 +2,14 @@ matrix:
|
|||||||
include:
|
include:
|
||||||
- os: osx
|
- os: osx
|
||||||
language: generic
|
language: generic
|
||||||
osx_image: xcode6.4
|
osx_image: xcode11.1
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- brew update
|
|
||||||
- brew install python3
|
|
||||||
- brew uninstall node
|
|
||||||
- travis_wait 30 brew install node@6
|
|
||||||
- brew link node@6 --force --overwrite
|
|
||||||
- pip3 install --upgrade pip setuptools wheel
|
- pip3 install --upgrade pip setuptools wheel
|
||||||
- openssl aes-256-cbc -K $encrypted_a95564d8ff0d_key -iv $encrypted_a95564d8ff0d_iv -in other/osx/sentry.py.enc -out kindlecomicconverter/sentry.py -d
|
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- pip3 install -r requirements.txt
|
- pip3 install -r requirements.txt
|
||||||
- pip3 install certifi https://github.com/bjones1/pyinstaller/archive/pyqt5_fix.zip
|
- pip3 install certifi https://github.com/pyinstaller/pyinstaller/archive/develop.zip
|
||||||
- npm install -g appdmg
|
- npm install -g appdmg
|
||||||
|
|
||||||
script: python3 setup.py build_binary
|
script: python3 setup.py build_binary
|
||||||
@@ -25,13 +19,12 @@ before_deploy:
|
|||||||
- rm -r dist/!(*.deb|*.dmg)
|
- rm -r dist/!(*.deb|*.dmg)
|
||||||
|
|
||||||
deploy:
|
deploy:
|
||||||
provider: s3
|
provider: gcs
|
||||||
skip_cleanup: true
|
access_key_id: GOOG1EC62457RKUYFR2TIZUWV4EFSV2EP5LVLPPFXUAKADWJFDYPFW63BQSLA
|
||||||
access_key_id: AKIAIQNL5R4FI4C4NJYQ
|
|
||||||
secret_access_key:
|
secret_access_key:
|
||||||
secure: X66hYplxB4QSueljwvDfamNH/MQmHjo3mCofBcaTHAr7n2fp+yd2NzD2yy9h8NbsL0LWwx9wtJa/jpkIE02ZDfi9NrMLvKKFazzdpiyTMN5Yh85lHHyD1XIOCZRd4igaZ+O8975tJAEaEOPS+PE9XGZcRBh+y/eSJ+fMEgohaJ1MtDFbQR7X1cEw3iqbjrV2rlghZNCk/9mZEfObzAEjQiSDpv5G0IuIPRvYg/BgZt8chHVAe03B6oqcBa7uCBCTlfHIiNh1MWtP0B3NNBq3dcu9QHOFri1YqoZKuaPVCf6TFQL/NW5dFihegev2t9IwFyaBxytiT8fBkgQhP0VX8cuCwBAfnQGIogAu0eLSPp+E6dB/7Cpt2GDCk39+As8WKqt9hCRHmrvYhPA1Mq9QyEgKy/TKKKfDby3qVTIqYOQYpuQ1B7sIU651L5A+hBvZ1dqWIUz25h0zqjjeSFrcfNnf1e4tkk0QJvvnKqz0xsVaJxA2p07VJMRn8SlZQIJ2GEbMDeB5jxYtf5JzXywChP9adlPNjLna9G8ScnGSU1f7ZhsBQUEgY5jBlnX1lveyl3DUe6NP+qOTyljLWYwjx3AF4Zg10LYSecRS6hnqAUrGRmibDCIYclUzlJkVyjKGJ9uEyrUiCp0P0IsAzE1XhPVAWEyGUcWWGJG+jgmohSk=
|
secure: sxYjeho7U3im0Ezf6cz6TjYDiLvf0kAM2ETQHYoFNbD1VVvhJJyymDCnPH80zpFKmhc1MWTB6ndwsrPfcyZDLR2meSdWGPjZfFPY3RcrfImndKi7ln+mYQDBQ7W1lGit4YcH3Ju7LHceaTbRA7fVTX8pWKOcbXL2oM+lQxTJHH32+crVma+ChhbjzTWsSLRoakt3Nhiveec5p/qSW7AFe4Zq+b3C85IgwjSJI/xVwzaWrs6p915h1zZi7KL7YCMIxfQFrvRPFR2KTbh/DoLCCrqfbD4qh0PVy1li51Ac3hd/u3foiNnTNchzgE3Nv/nbKmtFU6huuLNgzkQGuLA+yn7mKYzBwA3ZmFgoimdH9+yRCMkZ8B5VHpvfN1hgpJcyEl1T98Kv4cdtRYNB4w9iAMy1qSVxhjeI+2rjuWGoXro0lU6L4LIRCOruY3AuLCAKG8Qw5Ak9ksmIKBhZ9soxpoIwu/TYDUQkFj29IrUQucg9TEp7uAoxu8/7EHxB7hWnBRaBAAQbMuIRg7yysT3FT0Os6SB0t9+RBsVMSPuIti9JJZ2Lu0uRI1+Se+g7ItzYtJoPhBJAzAa+J9OONj0RNj2z8Vq2oIBhH4z6b6zTRMVroos3cdfYl5qIKs9SQ7rmeHoPRROcqpCznsUZ/ESa4f2MewFU/7AYcEnCesZV4xg=
|
||||||
bucket: kcc-deploy
|
bucket: kcc-deploy
|
||||||
region: eu-central-1
|
local-dir: dist
|
||||||
local_dir: dist
|
skip_cleanup: true
|
||||||
on:
|
on:
|
||||||
repo: AcidWeb/kcc
|
repo: AcidWeb/KCC
|
||||||
|
|||||||
70
AppImageBuilder.yml
Normal file
70
AppImageBuilder.yml
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
# appimage-builder recipe see https://appimage-builder.readthedocs.io for details
|
||||||
|
version: 1
|
||||||
|
script:
|
||||||
|
- rm -rf AppDir || true
|
||||||
|
- mkdir -p AppDir/usr/share/icons/hicolor/64x64/apps/
|
||||||
|
- cp -a dist/kcc_linux* AppDir/ && mv AppDir/kcc_linux* AppDir/kcc_linux
|
||||||
|
- cp icons/comic2ebook.png AppDir/usr/share/icons/hicolor/64x64/apps/
|
||||||
|
AppDir:
|
||||||
|
path: AppDir
|
||||||
|
app_info:
|
||||||
|
id: com.github.ciromattia.kcc
|
||||||
|
name: kindleComicConverter
|
||||||
|
icon: comic2ebook
|
||||||
|
version: latest
|
||||||
|
exec: ./kcc_linux
|
||||||
|
exec_args: $@
|
||||||
|
apt:
|
||||||
|
arch:
|
||||||
|
- amd64
|
||||||
|
allow_unauthenticated: true
|
||||||
|
sources:
|
||||||
|
- sourceline: deb http://archive.ubuntu.com/ubuntu focal main restricted
|
||||||
|
- sourceline: deb http://archive.ubuntu.com/ubuntu focal-updates main restricted
|
||||||
|
- sourceline: deb http://archive.ubuntu.com/ubuntu focal universe
|
||||||
|
- sourceline: deb http://archive.ubuntu.com/ubuntu focal-updates universe
|
||||||
|
- sourceline: deb http://archive.ubuntu.com/ubuntu focal multiverse
|
||||||
|
- sourceline: deb http://archive.ubuntu.com/ubuntu focal-updates multiverse
|
||||||
|
- sourceline: deb http://archive.ubuntu.com/ubuntu focal-backports main restricted
|
||||||
|
universe multiverse
|
||||||
|
- sourceline: deb http://security.ubuntu.com/ubuntu focal-security main restricted
|
||||||
|
- sourceline: deb http://security.ubuntu.com/ubuntu focal-security universe
|
||||||
|
- sourceline: deb http://security.ubuntu.com/ubuntu focal-security multiverse
|
||||||
|
include:
|
||||||
|
- zlib1g:amd64
|
||||||
|
files:
|
||||||
|
include:
|
||||||
|
- /lib/x86_64-linux-gnu/libGLX.so.0
|
||||||
|
- /lib/x86_64-linux-gnu/libGLdispatch.so.0
|
||||||
|
- /usr/lib/locale/locale-archive
|
||||||
|
exclude:
|
||||||
|
- usr/share/man
|
||||||
|
- usr/share/doc/*/README.*
|
||||||
|
- usr/share/doc/*/changelog.*
|
||||||
|
- usr/share/doc/*/NEWS.*
|
||||||
|
- usr/share/doc/*/TODO.*
|
||||||
|
test:
|
||||||
|
fedora-30:
|
||||||
|
image: appimagecrafters/tests-env:fedora-30
|
||||||
|
command: ./AppRun
|
||||||
|
use_host_x: true
|
||||||
|
debian-stable:
|
||||||
|
image: appimagecrafters/tests-env:debian-stable
|
||||||
|
command: ./AppRun
|
||||||
|
use_host_x: true
|
||||||
|
archlinux-latest:
|
||||||
|
image: appimagecrafters/tests-env:archlinux-latest
|
||||||
|
command: ./AppRun
|
||||||
|
use_host_x: true
|
||||||
|
centos-7:
|
||||||
|
image: appimagecrafters/tests-env:centos-7
|
||||||
|
command: ./AppRun
|
||||||
|
use_host_x: true
|
||||||
|
ubuntu-xenial:
|
||||||
|
image: appimagecrafters/tests-env:ubuntu-xenial
|
||||||
|
command: ./AppRun
|
||||||
|
use_host_x: true
|
||||||
|
AppImage:
|
||||||
|
arch: x86_64
|
||||||
|
update-information: !ENV ${UPDATE_INFO}
|
||||||
|
sign-key: None
|
||||||
55
CHANGELOG.md
55
CHANGELOG.md
@@ -1,4 +1,59 @@
|
|||||||
# CHANGELOG
|
# CHANGELOG
|
||||||
|
|
||||||
|
#### 5.6.1:
|
||||||
|
* Fix pillow backwards compatibility, add mozjpeg-lossless-optimization to setup.py by @corylk in #461
|
||||||
|
* fix in fedora: 7z doesn't support rar archives, use unrar by @AlicesReflexion in #370
|
||||||
|
* Using communicate instead of terminate by @catsout in #459
|
||||||
|
* use copyfile and delete instead of shutil.move fix #386 by @StudioEtrange in #387
|
||||||
|
|
||||||
|
|
||||||
|
#### 5.6.0:
|
||||||
|
* Fix Docker 7z missing [darodi/kcc#31](https://github.com/darodi/kcc/issues/31), thanks [@darodi](https://github.com/darodi)
|
||||||
|
* update to python 3.11, thanks [@darodi](https://github.com/darodi)
|
||||||
|
* Bump python from 3.8-slim-buster to 3.11-slim-buster dependabot[bot]
|
||||||
|
* More precise type in slugify dependency check, thanks [@bamless](https://github.com/bamless)
|
||||||
|
* Fix 'slugify' dependency check, thanks [@bamless](https://github.com/bamless)
|
||||||
|
* Update python-slugify requirement from <3.0.0,>=1.2.1 to >=1.2.1,<8.0.0 dependabot[bot]
|
||||||
|
* Bump actions/setup-python from 3 to 4 [darodi/kcc#32](https://github.com/darodi/kcc/issues/32) dependabot[bot]
|
||||||
|
* Bump actions/setup-node from 2 to 3 [darodi/kcc#34](https://github.com/darodi/kcc/issues/34) dependabot[bot]
|
||||||
|
* Fix Docker 7z missing [darodi/kcc#31](https://github.com/darodi/kcc/issues/31), thanks [@darodi](https://github.com/darodi)
|
||||||
|
* Spread splitter not keeping aspect ratio [darodi/kcc#27](https://github.com/darodi/kcc/issues/27), thanks [@darodi](https://github.com/darodi)
|
||||||
|
* activate batchsplit only for EPUB-200 [darodi/kcc#24](https://github.com/darodi/kcc/issues/24), thanks [@darodi](https://github.com/darodi)
|
||||||
|
* Feature Request: allow split for epub and set target (email, web upload) [darodi/kcc#21](https://github.com/darodi/kcc/issues/21), thanks [@darodi](https://github.com/darodi)
|
||||||
|
* Adding a switch on GUI interface in order to control cropping options [darodi/kcc#18](https://github.com/darodi/kcc/issues/18), thanks [@darodi](https://github.com/darodi)
|
||||||
|
* profiles: add Kindle11 and Kindle Scribe [darodi/kcc#16](https://github.com/darodi/kcc/issues/16), thanks [@darodi](https://github.com/darodi)
|
||||||
|
* Update with new Kobo models [darodi/kcc#15](https://github.com/darodi/kcc/issues/15), thanks [@lennie420](https://github.com/lennie420)
|
||||||
|
* Keep epub file when selecting another type of output file [darodi/kcc#12](https://github.com/darodi/kcc/issues/12), thanks [@darodi](https://github.com/darodi)
|
||||||
|
* fix Using 'Disable processing' option using my processed image get an error [darodi/kcc#1](https://github.com/darodi/kcc/issues/1), thanks [@darodi](https://github.com/darodi)
|
||||||
|
* KFX Output in GUI [darodi/kcc#9](https://github.com/darodi/kcc/issues/9), thanks [@darodi](https://github.com/darodi)
|
||||||
|
* Linux version and appImage [darodi/kcc#6](https://github.com/darodi/kcc/issues/6), thanks [@darodi](https://github.com/darodi)
|
||||||
|
* docker image for command line [darodi/kcc#5](https://github.com/darodi/kcc/issues/5), thanks [@darodi](https://github.com/darodi)
|
||||||
|
* Fix type error in autocontrastImage [ciromattia/kcc#432](https://github.com/ciromattia/kcc/issues/432), thanks [@darodi](https://github.com/darodi)
|
||||||
|
* Option to turn 1x4 strips into 2x2 strips [ciromattia/kcc#439](https://github.com/ciromattia/kcc/issues/439), thanks [@darodi](https://github.com/darodi)
|
||||||
|
* Option in GUI to have PNG instead of jpg images [darodi/kcc#3](https://github.com/darodi/kcc/issues/3), thanks [@darodi](https://github.com/darodi)
|
||||||
|
* Use MozJPEG as the JPEG encoder : cli and GUI option [ciromattia/kcc#416](https://github.com/ciromattia/kcc/pull/416), thanks [@darodi](https://github.com/darodi)
|
||||||
|
* Disable all image transformation : cli and GUI option [ciromattia/kcc#388](https://github.com/ciromattia/kcc/pull/388), thanks [@StudioEtrange](https://github.com/StudioEtrange)
|
||||||
|
* file selector add All `*.*` [ciromattia/kcc#412](https://github.com/ciromattia/kcc/pull/412), thanks [@StudioEtrange](https://github.com/StudioEtrange)
|
||||||
|
* Clarify Pillow version requirement [ciromattia/kcc#366](https://github.com/ciromattia/kcc/pull/366), thanks [@clach04](https://github.com/clach04)
|
||||||
|
* sync requirements between setup.py and requirements.txt [ciromattia/kcc#411](https://github.com/ciromattia/kcc/pull/411), thanks [@StudioEtrange](https://github.com/StudioEtrange)
|
||||||
|
* Add profile for Kindle PW5/Signature [ciromattia/kcc#405](https://github.com/ciromattia/kcc/pull/405), thanks [@Einlar](https://github.com/Einlar), [@darodi](https://github.com/darodi)
|
||||||
|
* Fixed the skipped/missed images and/or panels [ciromattia/kcc#393](https://github.com/ciromattia/kcc/pull/393), thanks [@FulyaDemirkan](https://github.com/FulyaDemirkan)
|
||||||
|
* Add profiles for the Kobo Clara HD and Libra H2O [ciromattia/kcc#331](https://github.com/ciromattia/kcc/pull/331), thanks [@fbriere](https://github.com/fbriere)
|
||||||
|
|
||||||
|
#### 5.5.2:
|
||||||
|
* Fixed KindleGen detection on macOS 10.15
|
||||||
|
* Fixed multiple smaller issues
|
||||||
|
|
||||||
|
#### 5.5.1:
|
||||||
|
* Fixes some stability issues
|
||||||
|
|
||||||
|
#### 5.5.0:
|
||||||
|
* Added support for WebP format
|
||||||
|
* Added profiles for Kindle Paperwhite 4 and Kobo Forma
|
||||||
|
* All archives are now handled by 7z
|
||||||
|
* Removed MCD support
|
||||||
|
* Fixed multiple smaller issues
|
||||||
|
|
||||||
#### 5.4.5:
|
#### 5.4.5:
|
||||||
* Fixed EPUB output for non-Kindle devices
|
* Fixed EPUB output for non-Kindle devices
|
||||||
|
|
||||||
|
|||||||
167
Dockerfile
Normal file
167
Dockerfile
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
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
|
||||||
|
FROM build-${TARGETARCH}${TARGETVARIANT}
|
||||||
|
LABEL com.kcc.name="Kindle Comic Converter"
|
||||||
|
LABEL com.kcc.author="Ciro Mattia Gonano, Paweł Jastrzębski and Darodi"
|
||||||
|
LABEL org.opencontainers.image.description='Kindle Comic Converter'
|
||||||
|
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
|
||||||
|
COPY . /opt/kcc
|
||||||
|
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 && \
|
||||||
|
cat /opt/kcc/kindlecomicconverter/__init__.py | grep version | awk '{print $3}' | sed "s/'//g" > /IMAGE_VERSION
|
||||||
|
|
||||||
|
ENTRYPOINT ["/opt/kcc/kcc-c2e.py"]
|
||||||
|
CMD ["-h"]
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
ISC LICENSE
|
ISC LICENSE
|
||||||
|
|
||||||
Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
||||||
Copyright (c) 2013-2018 Paweł Jastrzębski <pawelj@iosphe.re>
|
Copyright (c) 2013-2019 Paweł Jastrzębski <pawelj@iosphe.re>
|
||||||
|
Copyright (c) 2021-2023 Darodi
|
||||||
|
|
||||||
Permission to use, copy, modify, and/or distribute this software for
|
Permission to use, copy, modify, and/or distribute this software for
|
||||||
any purpose with or without fee is hereby granted, provided that the
|
any purpose with or without fee is hereby granted, provided that the
|
||||||
|
|||||||
339
README.md
339
README.md
@@ -1,6 +1,16 @@
|
|||||||
# KCC
|
# KCC
|
||||||
|
|
||||||
[](https://github.com/ciromattia/kcc/releases) [](https://pypi.python.org/pypi/KindleComicConverter) [](https://aur.archlinux.org/packages/kcc/)
|
[](https://github.com/ciromattia/kcc/releases)
|
||||||
|
[](https://test.pypi.org/project/KindleComicConverterDarodi/)
|
||||||
|
|
||||||
|
[](https://github.com/ciromattia/kcc/pkgs/container/kcc)
|
||||||
|
|
||||||
|
[//]: # ([](https://aur.archlinux.org/packages/kcc-beta))
|
||||||
|
|
||||||
|
|
||||||
|
[](https://github.com/ciromattia/kcc/releases)
|
||||||
|
[](https://pypi.python.org/pypi/KindleComicConverter)
|
||||||
|
[](https://aur.archlinux.org/packages/kcc/)
|
||||||
|
|
||||||
**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
|
||||||
@@ -10,7 +20,7 @@ It can also optionally optimize images by applying a number of transformations.
|
|||||||
### A word of warning
|
### A word of warning
|
||||||
**KCC** _is not_ [Amazon's Kindle Comic Creator](http://www.amazon.com/gp/feature.html?ie=UTF8&docId=1001103761) nor is in any way endorsed by Amazon.
|
**KCC** _is not_ [Amazon's Kindle Comic Creator](http://www.amazon.com/gp/feature.html?ie=UTF8&docId=1001103761) nor is in any way endorsed by Amazon.
|
||||||
Amazon's tool is for comic publishers and involves a lot of manual effort, while **KCC** is for comic/manga readers.
|
Amazon's tool is for comic publishers and involves a lot of manual effort, while **KCC** is for comic/manga readers.
|
||||||
_KC2_ in no way is a replacement for **KCC** so you can be quite confident we'll going to carry on developing our little monster ;-)
|
_KC2_ in no way is a replacement for **KCC** so you can be quite confident we are going to carry on developing our little monster ;-)
|
||||||
|
|
||||||
### Issues / new features / donations
|
### Issues / new features / donations
|
||||||
If you have general questions about usage, feedback etc. please [post it here](http://www.mobileread.com/forums/showthread.php?t=207461).
|
If you have general questions about usage, feedback etc. please [post it here](http://www.mobileread.com/forums/showthread.php?t=207461).
|
||||||
@@ -25,47 +35,247 @@ If you find **KCC** valuable you can consider donating to the authors:
|
|||||||
- [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=YTTJ4LK2JDHPS)
|
- [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=YTTJ4LK2JDHPS)
|
||||||
- [](https://jastrzeb.ski/donate/)
|
- [](https://jastrzeb.ski/donate/)
|
||||||
|
|
||||||
## BINARY RELEASES
|
|
||||||
You can find the latest released binary at the following links:
|
|
||||||
- **[Windows](http://kcc.iosphe.re/Windows/) (64-bit only)**
|
|
||||||
- **[macOS](http://kcc.iosphe.re/OSX/) (10.10+)**
|
|
||||||
- **Linux:**
|
|
||||||
- [Ubuntu 17.10](http://kcc.iosphe.re/LinuxArtful/)
|
|
||||||
- [Ubuntu 16.04 / Debian 9](http://kcc.iosphe.re/LinuxXenial/)
|
|
||||||
- [Ubuntu 14.04 / Debian 8](http://kcc.iosphe.re/LinuxTrusty/)
|
|
||||||
|
|
||||||
## PYPI
|
## INSTALLATION
|
||||||
**KCC** is also available on PyPI.
|
|
||||||
|
|
||||||
|
|
||||||
|
### BINARY RELEASES
|
||||||
|
You can find the latest binary at the following link:
|
||||||
|
|
||||||
|
- **https://github.com/ciromattia/kcc/releases**
|
||||||
|
|
||||||
|
|
||||||
|
~~- **[Windows](http://kcc.iosphe.re/Windows/) (64-bit only)**~~
|
||||||
|
~~- **[macOS](http://kcc.iosphe.re/OSX/) (10.14+)**~~
|
||||||
|
~~- **Linux:** Currently unavailable.~~
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#### MacOS installation
|
||||||
|
##### x86_64 version
|
||||||
|
see: KindleComicConverter_osx_*.dmg in **https://github.com/ciromattia/kcc/releases**
|
||||||
|
If you can't open the last beta and the OS says it's damaged, fix it with:
|
||||||
```
|
```
|
||||||
pip install KindleComicConverter
|
xattr -d com.apple.quarantine /Applications/Kindle\ Comic\ Converter.app
|
||||||
```
|
```
|
||||||
|
|
||||||
## DEPENDENCIES
|
##### 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
|
||||||
Following software is required to run Linux version of **KCC** and/or bare sources:
|
Following software is required to run Linux version of **KCC** and/or bare sources:
|
||||||
- Python 3.3+
|
- Python 3.3+
|
||||||
- [PyQt5](https://pypi.python.org/pypi/PyQt5) 5.6.0+
|
- [PyQt5](https://pypi.python.org/pypi/PyQt5) 5.6.0+ (only needed for GUI)
|
||||||
- [Pillow](https://pypi.python.org/pypi/Pillow/) 4.0.0+
|
- [Pillow](https://pypi.python.org/pypi/Pillow/) 4.0.0+ (5.2.0+ needed for WebP support)
|
||||||
- [psutil](https://pypi.python.org/pypi/psutil) 5.0.0+
|
- [psutil](https://pypi.python.org/pypi/psutil) 5.0.0+
|
||||||
- [python-slugify](https://pypi.python.org/pypi/python-slugify) 1.2.1+
|
- [python-slugify](https://pypi.python.org/pypi/python-slugify) 1.2.1+, <8.0.0
|
||||||
- [raven](https://pypi.python.org/pypi/raven) 6.0.0+
|
- [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 unrar
|
$ sudo apt-get install python3 python3-dev python3-pip libpng-dev libjpeg-dev p7zip-full python3-pyqt5
|
||||||
sudo pip3 install --upgrade pillow python-slugify psutil pyqt5 raven
|
|
||||||
|
$ pip3 install --user --upgrade pillow python-slugify psutil pyqt5 raven
|
||||||
```
|
```
|
||||||
|
|
||||||
### Optional dependencies
|
#### Optional dependencies
|
||||||
- [KindleGen](http://www.amazon.com/gp/feature.html?ie=UTF8&docId=1000765211) v2.9+ in a directory reachable by your _PATH_ or in _KCC_ directory *(For MOBI generation)*
|
- Qt platform integration plugin for Deepin Desktop Environment
|
||||||
- [UnRAR](http://www.rarlab.com/download.htm) *(For CBR/RAR support)*
|
```bash
|
||||||
- [7za](http://www.7-zip.org/download.html) *(For 7z/CB7 support)*
|
$ sudo apt-get install qt5dxcb-plugin
|
||||||
|
```
|
||||||
|
|
||||||
|
- KindleGen ~~[deprecated link](http://www.amazon.com/gp/feature.html?ie=UTF8&docId=1000765211)~~ v2.9+ in a directory reachable by your _PATH_ or in _KCC_ directory *(For MOBI generation)
|
||||||
|
– which offers a command line interface and supports [Linux](https://archive.org/details/kindlegen2.9) [(mirror1)](https://archive.org/download/kindlegen_linux_2_6_i386_v2_9/kindlegen_linux_2.6_i386_v2_9.tar.gz), [Mac OSX](https://web.archive.org/web/20190905040839/https://www.amazon.com/gp/feature.html?ie=UTF8&docId=1000765211) and [Windows](https://archive.org/details/kindlegen_win32_v2_9) – has been deprecated, but binaries can still be found on the internet.
|
||||||
|
- [7z](http://www.7-zip.org/download.html) *(For CBZ/ZIP, CBR/RAR, 7z/CB7 support)*
|
||||||
|
|
||||||
|
### INSTALL FROM SOURCES
|
||||||
|
|
||||||
|
_Originally posted by @hhtien1408 in https://github.com/ciromattia/kcc/issues/438#issuecomment-1281159452_
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ git clone https://github.com/ciromattia/kcc.git
|
||||||
|
```
|
||||||
|
On Debian based distributions these two commands should install all needed dependencies:
|
||||||
|
```bash
|
||||||
|
$ sudo apt-get install python3 python3-dev python3-pip libpng-dev libjpeg-dev p7zip-full python3-pyqt5
|
||||||
|
```
|
||||||
|
Then install the necessary packages. You can do it by running the following command. The requirements.txt file is inside this repository, you will see it when you clone the repo.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ pip3 install -r 'requirements.txt'
|
||||||
|
```
|
||||||
|
|
||||||
|
This should install the required packages. You can check the version by running
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ pip3 freeze
|
||||||
|
```
|
||||||
|
|
||||||
|
If the packages are in the wrong version, you can try to upgrade them by running
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ pip3 install --upgrade name_of_the_package
|
||||||
|
```
|
||||||
|
|
||||||
|
Download kindlegen.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ wget https://archive.org/download/kindlegen_linux_2_6_i386_v2_9/kindlegen_linux_2.6_i386_v2_9.tar.gz | tar xvzf kindlegen
|
||||||
|
```
|
||||||
|
Copy kindlegen into '/usr/local/bin' and grant execute permissions for MOBI conversion.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ sudo cp -R '/home/user/Desktop/kindlegen' '/usr/local/bin'
|
||||||
|
|
||||||
|
$ sudo chmod +rwx '/usr/local/bin/kindlegen'
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
Run python file for KCC GUI
|
||||||
|
```bash
|
||||||
|
$ python3 kcc.py
|
||||||
|
```
|
||||||
|
|
||||||
|
If everything goes well, you now should be able to use it.
|
||||||
|
|
||||||
|
Create destop file in '~/.local/share/applications' with codes:
|
||||||
|
|
||||||
|
```
|
||||||
|
#!/usr/bin/env xdg-open
|
||||||
|
|
||||||
|
[Desktop Entry]
|
||||||
|
Type=Application
|
||||||
|
Name=Kindle Comic Converter
|
||||||
|
Icon=kcc
|
||||||
|
Exec=python3 '/home/user/kcc/kcc.py'
|
||||||
|
Terminal=false
|
||||||
|
StartupWMClass=kcc
|
||||||
|
Name[en_US]=Kindle Comic Converter
|
||||||
|
```
|
||||||
|
|
||||||
|
Copy icon file into '/home/user/.local/share/icons'
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ sudo cp -R 'icons/comic2ebook.png' '/home/user/.local/share/icons'
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## INPUT FORMATS
|
## INPUT FORMATS
|
||||||
**KCC** can understand and convert, at the moment, the following input types:
|
**KCC** can understand and convert, at the moment, the following input types:
|
||||||
- Folders containing: PNG, JPG or GIF files
|
- Folders containing: PNG, JPG, GIF or WebP files
|
||||||
- CBZ, ZIP
|
- CBZ, ZIP *(With `7z` executable)*
|
||||||
- CBR, RAR *(With `unrar` executable)*
|
- CBR, RAR *(With `7z` executable)*
|
||||||
- CB7, 7Z *(With `7za` executable)*
|
- CB7, 7Z *(With `7z` executable)*
|
||||||
- PDF *(Only extracting JPG images)*
|
- PDF *(Only extracting JPG images)*
|
||||||
|
|
||||||
## USAGE
|
## USAGE
|
||||||
@@ -76,6 +286,41 @@ 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:
|
||||||
|
|
||||||
|
```
|
||||||
|
'K1': ("Kindle 1", (600, 670), Palette4, 1.8),
|
||||||
|
'K11': ("Kindle 11", (1072, 1448), Palette16, 1.8),
|
||||||
|
'K2': ("Kindle 2", (600, 670), Palette15, 1.8),
|
||||||
|
'K34': ("Kindle Keyboard/Touch", (600, 800), Palette16, 1.8),
|
||||||
|
'K578': ("Kindle", (600, 800), Palette16, 1.8),
|
||||||
|
'KDX': ("Kindle DX/DXG", (824, 1000), Palette16, 1.8),
|
||||||
|
'KPW': ("Kindle Paperwhite 1/2", (758, 1024), Palette16, 1.8),
|
||||||
|
'KV': ("Kindle Paperwhite 3/4/Voyage/Oasis", (1072, 1448), Palette16, 1.8),
|
||||||
|
'KPW5': ("Kindle Paperwhite 5/Signature Edition", (1236, 1648), Palette16, 1.8),
|
||||||
|
'KO': ("Kindle Oasis 2/3", (1264, 1680), Palette16, 1.8),
|
||||||
|
'KS': ("Kindle Scribe", (1860, 2480), Palette16, 1.8),
|
||||||
|
'KoMT': ("Kobo Mini/Touch", (600, 800), Palette16, 1.8),
|
||||||
|
'KoG': ("Kobo Glo", (768, 1024), Palette16, 1.8),
|
||||||
|
'KoGHD': ("Kobo Glo HD", (1072, 1448), Palette16, 1.8),
|
||||||
|
'KoA': ("Kobo Aura", (758, 1024), Palette16, 1.8),
|
||||||
|
'KoAHD': ("Kobo Aura HD", (1080, 1440), Palette16, 1.8),
|
||||||
|
'KoAH2O': ("Kobo Aura H2O", (1080, 1430), Palette16, 1.8),
|
||||||
|
'KoAO': ("Kobo Aura ONE", (1404, 1872), Palette16, 1.8),
|
||||||
|
'KoN': ("Kobo Nia", (758, 1024), Palette16, 1.8),
|
||||||
|
'KoC': ("Kobo Clara HD/Kobo Clara 2E", (1072, 1448), Palette16, 1.8),
|
||||||
|
'KoL': ("Kobo Libra H2O/Kobo Libra 2", (1264, 1680), Palette16, 1.8),
|
||||||
|
'KoF': ("Kobo Forma", (1440, 1920), Palette16, 1.8),
|
||||||
|
'KoS': ("Kobo Sage", (1440, 1920), Palette16, 1.8),
|
||||||
|
'KoE': ("Kobo Elipsa", (1404, 1872), Palette16, 1.8),
|
||||||
|
'OTHER': ("Other", (0, 0), Palette16, 1.8),
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
### Standalone `kcc-c2e.py` usage:
|
### Standalone `kcc-c2e.py` usage:
|
||||||
|
|
||||||
@@ -86,12 +331,16 @@ Options:
|
|||||||
MAIN:
|
MAIN:
|
||||||
-p PROFILE, --profile=PROFILE
|
-p PROFILE, --profile=PROFILE
|
||||||
Device profile (Available options: K1, K2, K34, K578,
|
Device profile (Available options: K1, K2, K34, K578,
|
||||||
KDX, KPW, KV, KO, KoMT, KoG, KoGHD, KoA, KoAHD, KoAH2O,
|
KDX, KPW, KPW5, KV, KO, K11, KS, KoMT, KoG, KoGHD,
|
||||||
KoAO) [Default=KV]
|
KoA, KoAHD, KoAH2O, KoAO, KoN, KoC, KoL, KoF, KoS,
|
||||||
|
KoE) [Default=KV]
|
||||||
-m, --manga-style Manga style (right-to-left reading and splitting)
|
-m, --manga-style Manga style (right-to-left reading and splitting)
|
||||||
-q, --hq Try to increase the quality of magnification
|
-q, --hq Try to increase the quality of magnification
|
||||||
-2, --two-panel Display two not four panels in Panel View mode
|
-2, --two-panel Display two not four panels in Panel View mode
|
||||||
-w, --webtoon Webtoon processing mode
|
-w, --webtoon Webtoon processing mode
|
||||||
|
--targetsize=TARGETSIZE
|
||||||
|
the maximal size of output file in MB. [Default=100MB
|
||||||
|
for webtoon and 400MB for others]
|
||||||
|
|
||||||
OUTPUT SETTINGS:
|
OUTPUT SETTINGS:
|
||||||
-o OUTPUT, --output=OUTPUT
|
-o OUTPUT, --output=OUTPUT
|
||||||
@@ -100,13 +349,15 @@ Options:
|
|||||||
Comic title [Default=filename or directory name]
|
Comic title [Default=filename or directory name]
|
||||||
-f FORMAT, --format=FORMAT
|
-f FORMAT, --format=FORMAT
|
||||||
Output format (Available options: Auto, MOBI, EPUB,
|
Output format (Available options: Auto, MOBI, EPUB,
|
||||||
CBZ, KFX) [Default=Auto]
|
CBZ, KFX, MOBI+EPUB) [Default=Auto]
|
||||||
-b BATCHSPLIT, --batchsplit=BATCHSPLIT
|
-b BATCHSPLIT, --batchsplit=BATCHSPLIT
|
||||||
Split output into multiple files. 0: Don't split 1:
|
Split output into multiple files. 0: Don't split 1:
|
||||||
Automatic mode 2: Consider every subdirectory as
|
Automatic mode 2: Consider every subdirectory as
|
||||||
separate volume [Default=0]
|
separate volume [Default=0]
|
||||||
|
|
||||||
PROCESSING:
|
PROCESSING:
|
||||||
|
-n, --noprocessing Do not modify image and ignore any profil or
|
||||||
|
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
|
||||||
@@ -124,6 +375,8 @@ Options:
|
|||||||
--whiteborders Disable autodetection and force white borders
|
--whiteborders Disable autodetection and force white borders
|
||||||
--forcecolor Don't convert images to grayscale
|
--forcecolor Don't convert images to grayscale
|
||||||
--forcepng Create PNG files instead JPEG
|
--forcepng Create PNG files instead JPEG
|
||||||
|
--mozjpeg Create JPEG files using mozJpeg
|
||||||
|
--maximizestrips Turn 1x4 strips to 2x2 strips
|
||||||
|
|
||||||
CUSTOM PROFILE:
|
CUSTOM PROFILE:
|
||||||
--customwidth=CUSTOMWIDTH
|
--customwidth=CUSTOMWIDTH
|
||||||
@@ -145,7 +398,8 @@ Options:
|
|||||||
-y HEIGHT, --height=HEIGHT
|
-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 splitting
|
-m, --merge Combine every directory into a single image before
|
||||||
|
splitting
|
||||||
|
|
||||||
OTHER:
|
OTHER:
|
||||||
-d, --debug Create debug file for every split image
|
-d, --debug Create debug file for every split image
|
||||||
@@ -153,36 +407,35 @@ Options:
|
|||||||
```
|
```
|
||||||
|
|
||||||
## CREDITS
|
## CREDITS
|
||||||
**KCC** is made by [Ciro Mattia Gonano](http://github.com/ciromattia) and [Paweł Jastrzębski](http://github.com/AcidWeb).
|
**KCC** is made by [Ciro Mattia Gonano](http://github.com/ciromattia), [Paweł Jastrzębski](http://github.com/AcidWeb) and [Darodi](http://github.com/darodi) .
|
||||||
|
|
||||||
This script born as a cross-platform alternative to `KindleComicParser` by **Dc5e** (published [here](http://www.mobileread.com/forums/showthread.php?t=192783)).
|
This script born as a cross-platform alternative to `KindleComicParser` by **Dc5e** (published [here](http://www.mobileread.com/forums/showthread.php?t=192783)).
|
||||||
|
|
||||||
The app relies and includes the following scripts:
|
The app relies and includes the following scripts:
|
||||||
|
|
||||||
- `DualMetaFix` script by **K. Hendricks**. Released with GPL-3 License.
|
- `DualMetaFix` script by **K. Hendricks**. Released with GPL-3 License.
|
||||||
- `rarfile.py` script © 2005-2014 **Marko Kreen** <markokr@gmail.com>. Released with ISC License.
|
|
||||||
- `image.py` class from **Alex Yatskov**'s [Mangle](https://github.com/FooSoft/mangle/) with subsequent [proDOOMman](https://github.com/proDOOMman/Mangle)'s and [Birua](https://github.com/Birua/Mangle)'s patches.
|
- `image.py` class from **Alex Yatskov**'s [Mangle](https://github.com/FooSoft/mangle/) with subsequent [proDOOMman](https://github.com/proDOOMman/Mangle)'s and [Birua](https://github.com/Birua/Mangle)'s patches.
|
||||||
- Icon is by **Nikolay Verin** ([http://ncrow.deviantart.com/](http://ncrow.deviantart.com/)) and released under [CC BY-NC-SA 3.0](http://creativecommons.org/licenses/by-nc-sa/3.0/) License.
|
- Icon is by **Nikolay Verin** ([http://ncrow.deviantart.com/](http://ncrow.deviantart.com/)) and released under [CC BY-NC-SA 3.0](http://creativecommons.org/licenses/by-nc-sa/3.0/) License.
|
||||||
|
|
||||||
## SAMPLE FILES CREATED BY KCC
|
## SAMPLE FILES CREATED BY KCC
|
||||||
* [Kindle Oasis 2](http://kcc.iosphe.re/Samples/Ubunchu!-KO.mobi)
|
* [Kindle Oasis 2 / 3](http://kcc.iosphe.re/Samples/Ubunchu!-KO.mobi)
|
||||||
* [Kindle Paperwhite 3 / Voyage / Oasis](http://kcc.iosphe.re/Samples/Ubunchu!-KV.mobi)
|
* [Kindle Paperwhite 3 / 4 / Voyage / Oasis](http://kcc.iosphe.re/Samples/Ubunchu!-KV.mobi)
|
||||||
* [Kindle Paperwhite 1 / 2](http://kcc.iosphe.re/Samples/Ubunchu!-KPW.mobi)
|
* [Kindle Paperwhite 1 / 2](http://kcc.iosphe.re/Samples/Ubunchu!-KPW.mobi)
|
||||||
* [Kindle](http://kcc.iosphe.re/Samples/Ubunchu!-K578.mobi)
|
* [Kindle](http://kcc.iosphe.re/Samples/Ubunchu!-K578.mobi)
|
||||||
* [Kobo Aura](http://kcc.iosphe.re/Samples/Ubunchu-KoA.kepub.epub)
|
* [Kobo Aura](http://kcc.iosphe.re/Samples/Ubunchu-KoA.kepub.epub)
|
||||||
* [Kobo Aura HD](http://kcc.iosphe.re/Samples/Ubunchu-KoAHD.kepub.epub)
|
* [Kobo Aura HD](http://kcc.iosphe.re/Samples/Ubunchu-KoAHD.kepub.epub)
|
||||||
* [Kobo Aura H2O](http://kcc.iosphe.re/Samples/Ubunchu-KoAH2O.kepub.epub)
|
* [Kobo Aura H2O](http://kcc.iosphe.re/Samples/Ubunchu-KoAH2O.kepub.epub)
|
||||||
* [Kobo Aura ONE](http://kcc.iosphe.re/Samples/Ubunchu-KoAO.kepub.epub)
|
* [Kobo Aura ONE](http://kcc.iosphe.re/Samples/Ubunchu-KoAO.kepub.epub)
|
||||||
|
* [Kobo Forma](http://kcc.iosphe.re/Samples/Ubunchu-KoF.kepub.epub)
|
||||||
|
|
||||||
## PRIVACY
|
## PRIVACY
|
||||||
**KCC** is initiating internet connections in three cases:
|
**KCC** is initiating internet connections in two cases:
|
||||||
* During startup - Version check
|
* During startup - Version check.
|
||||||
* When MCD metadata are used - Cover download
|
* When error occurs - Automatic reporting on Windows and macOS.
|
||||||
* When error occurs - Automatic reporting
|
|
||||||
|
|
||||||
## KNOWN ISSUES
|
## KNOWN ISSUES
|
||||||
Please check [wiki page](https://github.com/ciromattia/kcc/wiki/Known-issues).
|
Please check [wiki page](https://github.com/ciromattia/kcc/wiki/Known-issues).
|
||||||
|
|
||||||
## COPYRIGHT
|
## COPYRIGHT
|
||||||
Copyright (c) 2012-2018 Ciro Mattia Gonano and Paweł Jastrzębski.
|
Copyright (c) 2012-2023 Ciro Mattia Gonano, Paweł Jastrzębski and Darodi.
|
||||||
**KCC** is released under ISC LICENSE; see LICENSE.txt for further details.
|
**KCC** is released under ISC LICENSE; see [LICENSE.txt](./LICENSE.txt) for further details.
|
||||||
|
|||||||
320
application-vnd.appimage.svg
Normal file
320
application-vnd.appimage.svg
Normal file
@@ -0,0 +1,320 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="48px"
|
||||||
|
height="48px"
|
||||||
|
id="svg3832"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.47 r22583"
|
||||||
|
sodipodi:docname="appimage-assistant_alt3.svg">
|
||||||
|
<defs
|
||||||
|
id="defs3834">
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient3308-4-6-931-761-0"
|
||||||
|
id="linearGradient2975"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
x1="24.3125"
|
||||||
|
y1="22.96875"
|
||||||
|
x2="24.3125"
|
||||||
|
y2="41.03125" />
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient3308-4-6-931-761-0">
|
||||||
|
<stop
|
||||||
|
id="stop2919-2"
|
||||||
|
style="stop-color:#ffffff;stop-opacity:1"
|
||||||
|
offset="0" />
|
||||||
|
<stop
|
||||||
|
id="stop2921-76"
|
||||||
|
style="stop-color:#ffffff;stop-opacity:0"
|
||||||
|
offset="1" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient4222"
|
||||||
|
id="linearGradient2979"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(0,0.3704967,-0.3617496,0,33.508315,6.1670925)"
|
||||||
|
x1="7.6485429"
|
||||||
|
y1="26.437023"
|
||||||
|
x2="41.861729"
|
||||||
|
y2="26.437023" />
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient4222">
|
||||||
|
<stop
|
||||||
|
id="stop4224"
|
||||||
|
style="stop-color:#ffffff;stop-opacity:1"
|
||||||
|
offset="0" />
|
||||||
|
<stop
|
||||||
|
id="stop4226"
|
||||||
|
style="stop-color:#ffffff;stop-opacity:0"
|
||||||
|
offset="1" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient3308-4-6-931-761"
|
||||||
|
id="linearGradient2982"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="translate(0,0.9999987)"
|
||||||
|
x1="23.99999"
|
||||||
|
y1="4.999989"
|
||||||
|
x2="23.99999"
|
||||||
|
y2="43" />
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient3308-4-6-931-761">
|
||||||
|
<stop
|
||||||
|
id="stop2919"
|
||||||
|
style="stop-color:#ffffff;stop-opacity:1"
|
||||||
|
offset="0" />
|
||||||
|
<stop
|
||||||
|
id="stop2921"
|
||||||
|
style="stop-color:#ffffff;stop-opacity:0"
|
||||||
|
offset="1" />
|
||||||
|
</linearGradient>
|
||||||
|
<radialGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient3575"
|
||||||
|
id="radialGradient2985"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(0,1.0262008,-1.6561124,9.4072203e-4,-56.097482,-45.332325)"
|
||||||
|
cx="48.42384"
|
||||||
|
cy="-48.027504"
|
||||||
|
fx="48.42384"
|
||||||
|
fy="-48.027504"
|
||||||
|
r="38.212933" />
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient3575">
|
||||||
|
<stop
|
||||||
|
id="stop3577"
|
||||||
|
style="stop-color:#fafafa;stop-opacity:1"
|
||||||
|
offset="0" />
|
||||||
|
<stop
|
||||||
|
id="stop3579"
|
||||||
|
style="stop-color:#e6e6e6;stop-opacity:1"
|
||||||
|
offset="1" />
|
||||||
|
</linearGradient>
|
||||||
|
<radialGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient3993"
|
||||||
|
id="radialGradient2990"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(0,2.0478765,-2.7410544,-8.6412258e-8,47.161382,-8.837436)"
|
||||||
|
cx="9.3330879"
|
||||||
|
cy="8.4497671"
|
||||||
|
fx="9.3330879"
|
||||||
|
fy="8.4497671"
|
||||||
|
r="19.99999" />
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient3993">
|
||||||
|
<stop
|
||||||
|
offset="0"
|
||||||
|
style="stop-color:#a3c0d0;stop-opacity:1"
|
||||||
|
id="stop3995" />
|
||||||
|
<stop
|
||||||
|
offset="1"
|
||||||
|
style="stop-color:#427da1;stop-opacity:1"
|
||||||
|
id="stop4001" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient2508"
|
||||||
|
id="linearGradient2992"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="translate(0,0.9674382)"
|
||||||
|
x1="14.048676"
|
||||||
|
y1="44.137306"
|
||||||
|
x2="14.048676"
|
||||||
|
y2="4.0000005" />
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient2508">
|
||||||
|
<stop
|
||||||
|
offset="0"
|
||||||
|
style="stop-color:#2e4a5a;stop-opacity:1"
|
||||||
|
id="stop2510" />
|
||||||
|
<stop
|
||||||
|
offset="1"
|
||||||
|
style="stop-color:#6e8796;stop-opacity:1"
|
||||||
|
id="stop2512" />
|
||||||
|
</linearGradient>
|
||||||
|
<radialGradient
|
||||||
|
cx="4.9929786"
|
||||||
|
cy="43.5"
|
||||||
|
r="2.5"
|
||||||
|
fx="4.9929786"
|
||||||
|
fy="43.5"
|
||||||
|
id="radialGradient2873-966-168"
|
||||||
|
xlink:href="#linearGradient3688-166-749"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(2.003784,0,0,1.4,27.98813,-17.4)" />
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient3688-166-749">
|
||||||
|
<stop
|
||||||
|
id="stop2883"
|
||||||
|
style="stop-color:#181818;stop-opacity:1"
|
||||||
|
offset="0" />
|
||||||
|
<stop
|
||||||
|
id="stop2885"
|
||||||
|
style="stop-color:#181818;stop-opacity:0"
|
||||||
|
offset="1" />
|
||||||
|
</linearGradient>
|
||||||
|
<radialGradient
|
||||||
|
cx="4.9929786"
|
||||||
|
cy="43.5"
|
||||||
|
r="2.5"
|
||||||
|
fx="4.9929786"
|
||||||
|
fy="43.5"
|
||||||
|
id="radialGradient2875-742-326"
|
||||||
|
xlink:href="#linearGradient3688-464-309"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(2.003784,0,0,1.4,-20.01187,-104.4)" />
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient3688-464-309">
|
||||||
|
<stop
|
||||||
|
id="stop2889"
|
||||||
|
style="stop-color:#181818;stop-opacity:1"
|
||||||
|
offset="0" />
|
||||||
|
<stop
|
||||||
|
id="stop2891"
|
||||||
|
style="stop-color:#181818;stop-opacity:0"
|
||||||
|
offset="1" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
x1="25.058096"
|
||||||
|
y1="47.027729"
|
||||||
|
x2="25.058096"
|
||||||
|
y2="39.999443"
|
||||||
|
id="linearGradient2877-634-617"
|
||||||
|
xlink:href="#linearGradient3702-501-757"
|
||||||
|
gradientUnits="userSpaceOnUse" />
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient3702-501-757">
|
||||||
|
<stop
|
||||||
|
id="stop2895"
|
||||||
|
style="stop-color:#181818;stop-opacity:0"
|
||||||
|
offset="0" />
|
||||||
|
<stop
|
||||||
|
id="stop2897"
|
||||||
|
style="stop-color:#181818;stop-opacity:1"
|
||||||
|
offset="0.5" />
|
||||||
|
<stop
|
||||||
|
id="stop2899"
|
||||||
|
style="stop-color:#181818;stop-opacity:0"
|
||||||
|
offset="1" />
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="7"
|
||||||
|
inkscape:cx="24"
|
||||||
|
inkscape:cy="24"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="true"
|
||||||
|
inkscape:grid-bbox="true"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:window-width="603"
|
||||||
|
inkscape:window-height="484"
|
||||||
|
inkscape:window-x="417"
|
||||||
|
inkscape:window-y="162"
|
||||||
|
inkscape:window-maximized="0" />
|
||||||
|
<metadata
|
||||||
|
id="metadata3837">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
id="layer1"
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer">
|
||||||
|
<g
|
||||||
|
style="display:inline"
|
||||||
|
id="g2036"
|
||||||
|
transform="matrix(1.1,0,0,0.4444449,-2.4000022,25.11107)">
|
||||||
|
<g
|
||||||
|
style="opacity:0.4"
|
||||||
|
id="g3712"
|
||||||
|
transform="matrix(1.052632,0,0,1.285713,-1.263158,-13.42854)">
|
||||||
|
<rect
|
||||||
|
style="fill:url(#radialGradient2873-966-168);fill-opacity:1;stroke:none"
|
||||||
|
id="rect2801"
|
||||||
|
y="40"
|
||||||
|
x="38"
|
||||||
|
height="7"
|
||||||
|
width="5" />
|
||||||
|
<rect
|
||||||
|
style="fill:url(#radialGradient2875-742-326);fill-opacity:1;stroke:none"
|
||||||
|
id="rect3696"
|
||||||
|
transform="scale(-1,-1)"
|
||||||
|
y="-47"
|
||||||
|
x="-10"
|
||||||
|
height="7"
|
||||||
|
width="5" />
|
||||||
|
<rect
|
||||||
|
style="fill:url(#linearGradient2877-634-617);fill-opacity:1;stroke:none"
|
||||||
|
id="rect3700"
|
||||||
|
y="40"
|
||||||
|
x="10"
|
||||||
|
height="7.0000005"
|
||||||
|
width="28" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<rect
|
||||||
|
style="fill:url(#radialGradient2990);fill-opacity:1;stroke:url(#linearGradient2992);stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||||
|
id="rect5505"
|
||||||
|
y="5.4674392"
|
||||||
|
x="4.5"
|
||||||
|
ry="2.2322156"
|
||||||
|
rx="2.2322156"
|
||||||
|
height="39"
|
||||||
|
width="39" />
|
||||||
|
<path
|
||||||
|
style="opacity:0.05;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00178742;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||||
|
id="path4294-1"
|
||||||
|
d="m 21,6.9687498 a 2.0165107,2.0165107 0 0 0 -2.03125,2.03125 l 0,3.9687502 -1.15625,0 a 2.0165107,2.0165107 0 0 0 -1.5,3.375 l 5.0625,5.75 c -0.06312,0.110777 -0.178724,0.246032 -0.21875,0.34375 -0.195898,0.478256 -0.25,0.83653 -0.25,1.21875 l 0,0.125 L 20.8125,23.6875 C 20.534322,23.409323 20.213169,23.162739 19.71875,22.96875 19.47154,22.87176 19.185456,22.791748 18.75,22.8125 c -0.435456,0.02075 -1.054055,0.210302 -1.46875,0.625 L 15.75,24.96875 c -0.414689,0.414689 -0.604245,1.033294 -0.625,1.46875 -0.02075,0.435456 0.05925,0.721537 0.15625,0.96875 C 15.475241,27.900677 15.721817,28.221821 16,28.5 l 0.09375,0.09375 -0.125,0 c -0.382218,0 -0.740493,0.0541 -1.21875,0.25 -0.239128,0.09795 -0.538285,0.214988 -0.84375,0.53125 -0.305465,0.316262 -0.625,0.914788 -0.625,1.53125 l 0,2.1875 c 0,0.616465 0.319536,1.214989 0.625,1.53125 0.305464,0.316261 0.604622,0.433301 0.84375,0.53125 0.478256,0.195898 0.83653,0.25 1.21875,0.25 l 0.125,0 L 16,35.5 c -0.278175,0.278176 -0.52476,0.599329 -0.71875,1.09375 -0.09699,0.24721 -0.177003,0.533292 -0.15625,0.96875 0.02075,0.435458 0.210304,1.054058 0.625,1.46875 l 1.53125,1.53125 c 0.414691,0.414697 1.033292,0.604245 1.46875,0.625 0.435458,0.02076 0.721537,-0.05926 0.96875,-0.15625 0.494425,-0.19399 0.81557,-0.440568 1.09375,-0.71875 l 0.09375,-0.09375 0,0.125 c 0,0.38222 0.0541,0.740495 0.25,1.21875 0.09795,0.239127 0.214989,0.538285 0.53125,0.84375 0.316261,0.305465 0.914783,0.625 1.53125,0.625 l 2.1875,0 c 0.616466,0 1.214989,-0.319534 1.53125,-0.625 0.316261,-0.305466 0.433302,-0.604622 0.53125,-0.84375 0.195896,-0.478255 0.25,-0.836532 0.25,-1.21875 l 0,-0.125 0.09375,0.09375 c 0.278176,0.278175 0.599329,0.52476 1.09375,0.71875 0.24721,0.09699 0.533292,0.177003 0.96875,0.15625 0.435458,-0.02075 1.054058,-0.210304 1.46875,-0.625 L 32.875,39.03125 C 33.289697,38.616559 33.479245,37.997958 33.5,37.5625 33.52076,37.127042 33.44074,36.840963 33.34375,36.59375 33.14976,36.099325 32.903182,35.77818 32.625,35.5 l -0.09375,-0.09375 0.125,0 c 0.38222,0 0.740494,-0.0541 1.21875,-0.25 0.239128,-0.09795 0.538286,-0.214988 0.84375,-0.53125 0.305464,-0.316262 0.625,-0.914787 0.625,-1.53125 l 0,-2.1875 c 0,-0.61646 -0.319535,-1.214987 -0.625,-1.53125 -0.305465,-0.316263 -0.604621,-0.433301 -0.84375,-0.53125 -0.478257,-0.195898 -0.836532,-0.25 -1.21875,-0.25 l -0.125,0 L 32.625,28.5 c 0.278177,-0.278177 0.52476,-0.599329 0.71875,-1.09375 C 33.44074,27.15904 33.520753,26.872957 33.5,26.4375 33.47925,26.002043 33.289697,25.383443 32.875,24.96875 L 31.34375,23.4375 c -0.414688,-0.414694 -1.03329,-0.604245 -1.46875,-0.625 -0.43546,-0.02076 -0.721537,0.05925 -0.96875,0.15625 -0.494426,0.193991 -0.815572,0.44057 -1.09375,0.71875 l -0.09375,0.09375 0,-0.125 c 0,-0.382218 -0.0541,-0.740493 -0.25,-1.21875 -0.09112,-0.22245 -0.228127,-0.500183 -0.5,-0.78125 l 4.71875,-5.3125 a 2.0165107,2.0165107 0 0 0 -1.5,-3.375 l -1.15625,0 0,-3.9687502 A 2.0165107,2.0165107 0 0 0 27,6.9687498 l -6,0 z M 24.3125,31.25 c 0.427097,0 0.75,0.322904 0.75,0.75 0,0.427096 -0.322903,0.75 -0.75,0.75 -0.427094,0 -0.75,-0.322906 -0.75,-0.75 0,-0.427094 0.322906,-0.75 0.75,-0.75 z" />
|
||||||
|
<path
|
||||||
|
style="opacity:0.05;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00178742;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||||
|
id="path4294"
|
||||||
|
d="m 20.90625,8.0312498 a 0.96385067,0.96385067 0 0 0 -0.875,0.96875 l 0,5.0312502 -2.21875,0 A 0.96385067,0.96385067 0 0 0 17.09375,15.625 l 5.78125,6.53125 c -0.158814,0.0616 -0.341836,0.0951 -0.4375,0.1875 -0.169161,0.163386 -0.252971,0.323419 -0.3125,0.46875 -0.119058,0.290663 -0.15625,0.566746 -0.15625,0.84375 l 0,1.65625 C 21.718163,25.40233 21.485871,25.509772 21.25,25.625 l -1.1875,-1.1875 c -0.199651,-0.19965 -0.421433,-0.352095 -0.71875,-0.46875 -0.148659,-0.05833 -0.329673,-0.104846 -0.5625,-0.09375 -0.232827,0.0111 -0.53583,0.09833 -0.75,0.3125 L 16.5,25.71875 c -0.214168,0.214168 -0.301403,0.517173 -0.3125,0.75 -0.0111,0.232827 0.03542,0.41384 0.09375,0.5625 0.116655,0.297321 0.269096,0.519099 0.46875,0.71875 l 1.1875,1.1875 c -0.115228,0.235871 -0.222668,0.468163 -0.3125,0.71875 l -1.65625,0 c -0.277003,0 -0.553087,0.03719 -0.84375,0.15625 -0.145332,0.05953 -0.305363,0.143338 -0.46875,0.3125 -0.163387,0.169162 -0.3125,0.46403 -0.3125,0.78125 l 0,2.1875 c 0,0.317221 0.149114,0.612089 0.3125,0.78125 0.163386,0.169161 0.323419,0.252971 0.46875,0.3125 0.290663,0.119058 0.566746,0.15625 0.84375,0.15625 l 1.65625,0 c 0.08983,0.250587 0.197272,0.482879 0.3125,0.71875 L 16.75,36.25 c -0.199649,0.19965 -0.352095,0.421432 -0.46875,0.71875 -0.05833,0.148659 -0.104846,0.329672 -0.09375,0.5625 0.0111,0.232828 0.09833,0.535831 0.3125,0.75 l 1.53125,1.53125 c 0.214168,0.214172 0.517172,0.301403 0.75,0.3125 0.232828,0.0111 0.41384,-0.03542 0.5625,-0.09375 0.29732,-0.116655 0.519098,-0.269096 0.71875,-0.46875 L 21.25,38.375 c 0.235871,0.115228 0.468164,0.222668 0.71875,0.3125 l 0,1.65625 c 0,0.277003 0.03719,0.553087 0.15625,0.84375 0.05953,0.145331 0.143339,0.305364 0.3125,0.46875 0.169161,0.163386 0.464028,0.3125 0.78125,0.3125 l 2.1875,0 c 0.317221,0 0.612089,-0.149113 0.78125,-0.3125 0.169161,-0.163387 0.252971,-0.323419 0.3125,-0.46875 0.119057,-0.290663 0.15625,-0.566748 0.15625,-0.84375 l 0,-1.65625 c 0.250586,-0.08983 0.482879,-0.197272 0.71875,-0.3125 l 1.1875,1.1875 c 0.19965,0.199649 0.421432,0.352095 0.71875,0.46875 0.148659,0.05833 0.329672,0.104846 0.5625,0.09375 0.232828,-0.0111 0.535831,-0.09833 0.75,-0.3125 L 32.125,38.28125 c 0.214172,-0.214168 0.301403,-0.517172 0.3125,-0.75 0.0111,-0.232828 -0.03542,-0.41384 -0.09375,-0.5625 C 32.227095,36.67143 32.074654,36.449652 31.875,36.25 L 30.6875,35.0625 C 30.802728,34.82663 30.910168,34.594337 31,34.34375 l 1.65625,0 c 0.277004,0 0.553087,-0.03719 0.84375,-0.15625 0.145332,-0.05953 0.305364,-0.143339 0.46875,-0.3125 0.163386,-0.169161 0.3125,-0.46403 0.3125,-0.78125 l 0,-2.1875 c 0,-0.317219 -0.149114,-0.612088 -0.3125,-0.78125 C 33.805364,29.955838 33.645332,29.872029 33.5,29.8125 33.209336,29.693442 32.933253,29.65625 32.65625,29.65625 l -1.65625,0 C 30.91017,29.405663 30.802728,29.17337 30.6875,28.9375 L 31.875,27.75 c 0.19965,-0.19965 0.352095,-0.421432 0.46875,-0.71875 0.05833,-0.148659 0.104846,-0.329672 0.09375,-0.5625 -0.0111,-0.232828 -0.09833,-0.535831 -0.3125,-0.75 L 30.59375,24.1875 c -0.214167,-0.21417 -0.517171,-0.301403 -0.75,-0.3125 -0.232829,-0.0111 -0.41384,0.03542 -0.5625,0.09375 -0.29732,0.116656 -0.519099,0.269097 -0.71875,0.46875 L 27.375,25.625 c -0.235871,-0.115228 -0.468163,-0.222668 -0.71875,-0.3125 l 0,-1.65625 c 0,-0.277003 -0.03719,-0.553087 -0.15625,-0.84375 -0.05953,-0.145332 -0.143338,-0.305363 -0.3125,-0.46875 -0.169162,-0.163387 -0.46403,-0.3125 -0.78125,-0.3125 l -0.15625,0 5.65625,-6.40625 A 0.96385067,0.96385067 0 0 0 30.1875,14.03125 l -2.21875,0 0,-5.0312502 A 0.96385067,0.96385067 0 0 0 27,8.0312498 l -6,0 a 0.96385067,0.96385067 0 0 0 -0.09375,0 z M 24.3125,30.1875 c 1.002113,0 1.8125,0.810388 1.8125,1.8125 0,1.002112 -0.810387,1.8125 -1.8125,1.8125 C 23.31039,33.8125 22.5,33.002111 22.5,32 c 0,-1.002111 0.81039,-1.8125 1.8125,-1.8125 z" />
|
||||||
|
<path
|
||||||
|
style="fill:url(#radialGradient2985);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00178742;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||||
|
id="path2317"
|
||||||
|
d="M 21,8.9999996 21,15 17.8125,15 24,22 30.1875,15 27,15 l 0,-6.0000004 -6,0 z M 23.21875,23 c -0.172892,0 -0.28125,0.294922 -0.28125,0.65625 l 0,2.28125 C 22.24145,26.095996 21.585954,26.379869 21,26.75 l -1.625,-1.625 c -0.255498,-0.255497 -0.533998,-0.372253 -0.65625,-0.25 l -1.53125,1.53125 c -0.122254,0.122254 -0.0055,0.400753 0.25,0.65625 l 1.625,1.625 c -0.37013,0.585953 -0.654003,1.24145 -0.8125,1.9375 l -2.28125,0 c -0.361328,0 -0.65625,0.108357 -0.65625,0.28125 l 0,2.1875 c 0,0.172892 0.294922,0.28125 0.65625,0.28125 l 2.28125,0 c 0.158497,0.69605 0.44237,1.351546 0.8125,1.9375 l -1.625,1.625 c -0.255497,0.255498 -0.372254,0.533997 -0.25,0.65625 l 1.53125,1.53125 c 0.122252,0.122254 0.400752,0.0055 0.65625,-0.25 L 21,37.25 c 0.585954,0.37013 1.24145,0.654002 1.9375,0.8125 l 0,2.28125 C 22.9375,40.705077 23.045858,41 23.21875,41 l 2.1875,0 c 0.172893,0 0.28125,-0.294924 0.28125,-0.65625 l 0,-2.28125 c 0.69605,-0.158498 1.351546,-0.44237 1.9375,-0.8125 l 1.625,1.625 c 0.255498,0.255497 0.533997,0.372254 0.65625,0.25 l 1.53125,-1.53125 c 0.122254,-0.122252 0.0055,-0.400752 -0.25,-0.65625 l -1.625,-1.625 c 0.370129,-0.585954 0.654003,-1.24145 0.8125,-1.9375 l 2.28125,0 c 0.361329,0 0.65625,-0.108358 0.65625,-0.28125 l 0,-2.1875 c 0,-0.172893 -0.294921,-0.28125 -0.65625,-0.28125 l -2.28125,0 c -0.158497,-0.69605 -0.442371,-1.351547 -0.8125,-1.9375 l 1.625,-1.625 c 0.255497,-0.255497 0.372254,-0.533997 0.25,-0.65625 L 29.90625,24.875 C 29.783997,24.752745 29.505498,24.8695 29.25,25.125 l -1.625,1.625 c -0.585954,-0.370131 -1.24145,-0.654004 -1.9375,-0.8125 l 0,-2.28125 C 25.6875,23.294922 25.579143,23 25.40625,23 l -2.1875,0 z m 1.09375,6.21875 c 1.528616,0 2.78125,1.252635 2.78125,2.78125 0,1.528615 -1.252634,2.78125 -2.78125,2.78125 -1.528614,0 -2.78125,-1.252635 -2.78125,-2.78125 0,-1.528615 1.252636,-2.78125 2.78125,-2.78125 z" />
|
||||||
|
<rect
|
||||||
|
style="opacity:0.4;fill:none;stroke:url(#linearGradient2982);stroke-width:0.99999976;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||||
|
id="rect6741"
|
||||||
|
y="6.4999886"
|
||||||
|
x="5.4999981"
|
||||||
|
ry="1.365193"
|
||||||
|
rx="1.365193"
|
||||||
|
height="37.000011"
|
||||||
|
width="36.999985" />
|
||||||
|
<path
|
||||||
|
style="fill:none;stroke:url(#linearGradient2979);stroke-width:0.99829447;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
|
||||||
|
id="path2777"
|
||||||
|
d="M 28.926376,15.466668 24,21.177578 18.963089,15.5 21.5,15.5 l 0,-6.0000004 5,0 0,6.0000004 2.426376,-0.03333 z" />
|
||||||
|
<path
|
||||||
|
style="fill:none;stroke:url(#linearGradient2975);stroke-width:1;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||||
|
id="path4243"
|
||||||
|
d="m 23.4375,23.46875 c -0.01166,0.05381 -0.03125,0.100205 -0.03125,0.1875 l 0,2.28125 a 0.48185467,0.48185467 0 0 1 -0.375,0.46875 c -0.638467,0.145384 -1.238423,0.407111 -1.78125,0.75 a 0.48185467,0.48185467 0 0 1 -0.59375,-0.0625 l -1.625,-1.625 C 18.9779,25.4154 18.9477,25.40242 18.90625,25.375 l -1.21875,1.21875 c 0.02742,0.04145 0.0404,0.07165 0.09375,0.125 l 1.625,1.625 a 0.48185467,0.48185467 0 0 1 0.0625,0.59375 c -0.342888,0.542826 -0.604615,1.142782 -0.75,1.78125 a 0.48185467,0.48185467 0 0 1 -0.46875,0.375 l -2.28125,0 c -0.08729,0 -0.133695,0.01959 -0.1875,0.03125 l 0,1.75 c 0.05381,0.01166 0.100205,0.03125 0.1875,0.03125 l 2.28125,0 a 0.48185467,0.48185467 0 0 1 0.46875,0.375 c 0.145385,0.638468 0.407112,1.238423 0.75,1.78125 a 0.48185467,0.48185467 0 0 1 -0.0625,0.59375 l -1.625,1.625 c -0.05335,0.05335 -0.06633,0.08355 -0.09375,0.125 l 1.21875,1.21875 c 0.04145,-0.02742 0.07165,-0.0404 0.125,-0.09375 l 1.625,-1.625 A 0.48185467,0.48185467 0 0 1 21.25,36.84375 c 0.542827,0.342888 1.142781,0.604614 1.78125,0.75 a 0.48185467,0.48185467 0 0 1 0.375,0.46875 l 0,2.28125 c 0,0.08729 0.01959,0.133695 0.03125,0.1875 l 1.75,0 c 0.01166,-0.0538 0.03125,-0.100206 0.03125,-0.1875 l 0,-2.28125 a 0.48185467,0.48185467 0 0 1 0.375,-0.46875 c 0.638469,-0.145386 1.238423,-0.407112 1.78125,-0.75 a 0.48185467,0.48185467 0 0 1 0.59375,0.0625 l 1.625,1.625 c 0.05335,0.05335 0.08355,0.06633 0.125,0.09375 l 1.21875,-1.21875 c -0.02742,-0.04145 -0.0404,-0.07165 -0.09375,-0.125 l -1.625,-1.625 a 0.48185467,0.48185467 0 0 1 -0.0625,-0.59375 c 0.342888,-0.542828 0.604615,-1.142783 0.75,-1.78125 a 0.48185467,0.48185467 0 0 1 0.46875,-0.375 l 2.28125,0 c 0.08729,0 0.133695,-0.01959 0.1875,-0.03125 l 0,-1.75 c -0.0538,-0.01166 -0.100204,-0.03125 -0.1875,-0.03125 l -2.28125,0 a 0.48185467,0.48185467 0 0 1 -0.46875,-0.375 c -0.145385,-0.638467 -0.407113,-1.238424 -0.75,-1.78125 a 0.48185467,0.48185467 0 0 1 0.0625,-0.59375 l 1.625,-1.625 c 0.05335,-0.05335 0.06633,-0.08355 0.09375,-0.125 L 29.71875,25.375 c -0.04145,0.02742 -0.07165,0.0404 -0.125,0.09375 l -1.625,1.625 a 0.48185467,0.48185467 0 0 1 -0.59375,0.0625 c -0.542827,-0.342889 -1.142783,-0.604616 -1.78125,-0.75 a 0.48185467,0.48185467 0 0 1 -0.375,-0.46875 l 0,-2.28125 c 0,-0.0873 -0.01959,-0.133695 -0.03125,-0.1875 l -1.75,0 z m 0.875,5.28125 c 1.791829,0 3.25,1.458172 3.25,3.25 0,1.791828 -1.458171,3.25 -3.25,3.25 -1.791827,0 -3.25,-1.458172 -3.25,-3.25 0,-1.791828 1.458173,-3.25 3.25,-3.25 z" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 21 KiB |
21
appveyor.yml
21
appveyor.yml
@@ -1,25 +1,14 @@
|
|||||||
environment:
|
environment:
|
||||||
PYTHON: "C:\\Python36-x64"
|
PYTHON: "C:\\Python37-x64"
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- set PATH="%PYTHON%\\Scripts";"C:\\Program Files (x86)\\Inno Setup 5";%PATH%
|
- set PATH="%PYTHON%\\Scripts";%PATH%
|
||||||
- "%PYTHON%\\python.exe -m pip install --upgrade pip setuptools wheel"
|
- "%PYTHON%\\python.exe -m pip install --upgrade pip setuptools wheel"
|
||||||
- "%PYTHON%\\python.exe -m pip install -r requirements.txt"
|
- "%PYTHON%\\python.exe -m pip install -r requirements.txt"
|
||||||
- "%PYTHON%\\python.exe -m pip install certifi https://github.com/bjones1/pyinstaller/archive/pyqt5_fix.zip"
|
- "%PYTHON%\\python.exe -m pip install certifi https://github.com/pyinstaller/pyinstaller/archive/develop.zip"
|
||||||
- nuget install secure-file -ExcludeVersion
|
|
||||||
- secure-file\tools\secure-file -decrypt other\windows\sentry.py.enc -out kindlecomicconverter\sentry.py -secret %ENCRYPTION%
|
|
||||||
|
|
||||||
build_script:
|
build_script:
|
||||||
- "%PYTHON%\\python.exe setup.py build_binary"
|
- "%PYTHON%\\python.exe setup.py build_binary"
|
||||||
|
|
||||||
after_build:
|
artifacts:
|
||||||
- ps: Get-ChildItem .\dist\KCC* | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name }
|
- path: dist\KCC*
|
||||||
|
|
||||||
deploy:
|
|
||||||
provider: S3
|
|
||||||
access_key_id:
|
|
||||||
secure: pWfyU8wtAHt354mBILwM41TemOjb+My9n3CRMnrpLzI=
|
|
||||||
secret_access_key:
|
|
||||||
secure: G0Xpxe355LMqV3s8v+TsdJYdmhFoKKA+mxK37Tlu8yNwKXKJgcnY7pcFKSdX5xS5
|
|
||||||
bucket: kcc-deploy
|
|
||||||
region: eu-central-1
|
|
||||||
|
|||||||
11
gen_ui_files.bat
Normal file
11
gen_ui_files.bat
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
|
||||||
|
REM install qt creator
|
||||||
|
REM conda create -n qtenv python=3.7
|
||||||
|
REM conda activate qtenv
|
||||||
|
REM pip install PyQt5
|
||||||
|
|
||||||
|
pyuic5 gui/KCC.ui > kindlecomicconverter/KCC_ui.py
|
||||||
|
|
||||||
|
pyuic5 gui/MetaEditor.ui > kindlecomicconverter/KCC_ui_editor.py
|
||||||
|
|
||||||
|
pyrcc5 gui/KCC.qrc > kindlecomicconverter/KCC_rc.py
|
||||||
10
gen_ui_files.sh
Executable file
10
gen_ui_files.sh
Executable file
@@ -0,0 +1,10 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# PREPARE PYTHON ENV
|
||||||
|
# conda create -n pyqt5 python=3.7
|
||||||
|
# source activate pyqt5
|
||||||
|
# pip install pyqt5
|
||||||
|
|
||||||
|
pyuic5 gui/KCC.ui --from-imports > kindlecomicconverter/KCC_ui.py
|
||||||
|
pyuic5 gui/MetaEditor.ui --from-imports > kindlecomicconverter/KCC_ui_editor.py
|
||||||
|
pyrcc5 gui/KCC.qrc > kindlecomicconverter/KCC_rc.py
|
||||||
@@ -11,6 +11,7 @@
|
|||||||
<file>../icons/CBZ.png</file>
|
<file>../icons/CBZ.png</file>
|
||||||
<file>../icons/EPUB.png</file>
|
<file>../icons/EPUB.png</file>
|
||||||
<file>../icons/MOBI.png</file>
|
<file>../icons/MOBI.png</file>
|
||||||
|
<file>../icons/KFX.png</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
<qresource prefix="Status">
|
<qresource prefix="Status">
|
||||||
<file>../icons/error.png</file>
|
<file>../icons/error.png</file>
|
||||||
|
|||||||
434
gui/KCC.ui
434
gui/KCC.ui
@@ -22,118 +22,7 @@
|
|||||||
<property name="bottomMargin">
|
<property name="bottomMargin">
|
||||||
<number>5</number>
|
<number>5</number>
|
||||||
</property>
|
</property>
|
||||||
<item row="1" column="0" colspan="2">
|
<item row="5" column="0" colspan="2">
|
||||||
<widget class="QProgressBar" name="progressBar">
|
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>0</width>
|
|
||||||
<height>30</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="font">
|
|
||||||
<font>
|
|
||||||
<weight>75</weight>
|
|
||||||
<bold>true</bold>
|
|
||||||
</font>
|
|
||||||
</property>
|
|
||||||
<property name="visible">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<property name="alignment">
|
|
||||||
<set>Qt::AlignJustify|Qt::AlignVCenter</set>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="2" column="0" colspan="2">
|
|
||||||
<widget class="QListWidget" name="jobList">
|
|
||||||
<property name="styleSheet">
|
|
||||||
<string notr="true">QListWidget#jobList {background:#ffffff;background-image:url(:/Other/icons/list_background.png);background-position:center center;background-repeat:no-repeat;color:rgb(0,0,0);}</string>
|
|
||||||
</property>
|
|
||||||
<property name="selectionMode">
|
|
||||||
<enum>QAbstractItemView::NoSelection</enum>
|
|
||||||
</property>
|
|
||||||
<property name="verticalScrollMode">
|
|
||||||
<enum>QAbstractItemView::ScrollPerPixel</enum>
|
|
||||||
</property>
|
|
||||||
<property name="horizontalScrollMode">
|
|
||||||
<enum>QAbstractItemView::ScrollPerPixel</enum>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="6" column="0" colspan="2">
|
|
||||||
<widget class="QWidget" name="customWidget" native="true">
|
|
||||||
<property name="visible">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<layout class="QGridLayout" name="gridLayout_3">
|
|
||||||
<property name="leftMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="topMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="rightMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="bottomMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<item row="0" column="2">
|
|
||||||
<widget class="QLabel" name="hLabel">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="toolTip">
|
|
||||||
<string><html><head/><body><p style='white-space:pre'>Resolution of the target device.</p></body></html></string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Custom height:</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="1">
|
|
||||||
<widget class="QSpinBox" name="widthBox">
|
|
||||||
<property name="toolTip">
|
|
||||||
<string><html><head/><body><p style='white-space:pre'>Resolution of the target device.</p></body></html></string>
|
|
||||||
</property>
|
|
||||||
<property name="maximum">
|
|
||||||
<number>2160</number>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="0">
|
|
||||||
<widget class="QLabel" name="wLabel">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="toolTip">
|
|
||||||
<string><html><head/><body><p style='white-space:pre'>Resolution of the target device.</p></body></html></string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Custom width:</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="3">
|
|
||||||
<widget class="QSpinBox" name="heightBox">
|
|
||||||
<property name="toolTip">
|
|
||||||
<string><html><head/><body><p style='white-space:pre'>Resolution of the target device.</p></body></html></string>
|
|
||||||
</property>
|
|
||||||
<property name="maximum">
|
|
||||||
<number>3840</number>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="4" column="0" colspan="2">
|
|
||||||
<widget class="QWidget" name="optionWidget" native="true">
|
<widget class="QWidget" name="optionWidget" native="true">
|
||||||
<layout class="QGridLayout" name="gridLayout_2">
|
<layout class="QGridLayout" name="gridLayout_2">
|
||||||
<property name="leftMargin">
|
<property name="leftMargin">
|
||||||
@@ -148,13 +37,16 @@
|
|||||||
<property name="bottomMargin">
|
<property name="bottomMargin">
|
||||||
<number>0</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
<item row="0" column="0">
|
<item row="1" column="1">
|
||||||
<widget class="QCheckBox" name="mangaBox">
|
<widget class="QCheckBox" name="upscaleBox">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string><html><head/><body><p style='white-space:pre'>Enable right-to-left reading.</p></body></html></string>
|
<string><html><head/><body><p><span style=" font-weight:600; text-decoration: underline;">Unchecked - Nothing<br/></span>Images smaller than device resolution will not be resized.</p><p><span style=" font-weight:600; text-decoration: underline;">Indeterminate - Stretching<br/></span>Images smaller than device resolution will be resized. Aspect ratio will be not preserved.</p><p><span style=" font-weight:600; text-decoration: underline;">Checked - Upscaling<br/></span>Images smaller than device resolution will be resized. Aspect ratio will be preserved.</p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Manga mode</string>
|
<string>Stretch/Upscale</string>
|
||||||
|
</property>
|
||||||
|
<property name="tristate">
|
||||||
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@@ -171,16 +63,13 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="2">
|
<item row="2" column="1">
|
||||||
<widget class="QCheckBox" name="qualityBox">
|
<widget class="QCheckBox" name="outputSplit">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string><html><head/><body><p style='white-space:pre'><span style=" font-weight:600; text-decoration: underline;">Unchecked - 4 panels<br/></span>Zoom each corner separately.</p><p style='white-space:pre'><span style=" font-weight:600; text-decoration: underline;">Indeterminate - 2 panels<br/></span>Zoom only the top and bottom of the page.</p><p><span style=" font-weight:600; text-decoration: underline;">Checked - 4 high-quality panels<br/></span>Zoom each corner separately. Try to increase the quality of magnification. Check wiki for more details.</p></body></html></string>
|
<string><html><head/><body><p style='white-space:pre'><span style=" font-weight:600; text-decoration: underline;">Unchecked - Automatic mode<br/></span>The output will be split automatically.</p><p style='white-space:pre'><span style=" font-weight:600; text-decoration: underline;">Checked - Volume mode<br/></span>Every subdirectory will be considered as a separate volume.</p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Panel View 4/2/HQ</string>
|
<string>Output split</string>
|
||||||
</property>
|
|
||||||
<property name="tristate">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@@ -194,16 +83,13 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="1">
|
<item row="2" column="2">
|
||||||
<widget class="QCheckBox" name="upscaleBox">
|
<widget class="QCheckBox" name="colorBox">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string><html><head/><body><p><span style=" font-weight:600; text-decoration: underline;">Unchecked - Nothing<br/></span>Images smaller than device resolution will not be resized.</p><p><span style=" font-weight:600; text-decoration: underline;">Indeterminate - Stretching<br/></span>Images smaller than device resolution will be resized. Aspect ratio will be not preserved.</p><p><span style=" font-weight:600; text-decoration: underline;">Checked - Upscaling<br/></span>Images smaller than device resolution will be resized. Aspect ratio will be preserved.</p></body></html></string>
|
<string><html><head/><body><p style='white-space:pre'>Disable conversion to grayscale.</p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Stretch/Upscale</string>
|
<string>Color mode</string>
|
||||||
</property>
|
|
||||||
<property name="tristate">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@@ -230,30 +116,79 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="1">
|
<item row="0" column="0">
|
||||||
<widget class="QCheckBox" name="outputSplit">
|
<widget class="QCheckBox" name="mangaBox">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string><html><head/><body><p style='white-space:pre'><span style=" font-weight:600; text-decoration: underline;">Unchecked - Automatic mode<br/></span>The output will be split automatically.</p><p style='white-space:pre'><span style=" font-weight:600; text-decoration: underline;">Checked - Volume mode<br/></span>Every subdirectory will be considered as a separate volume.</p></body></html></string>
|
<string><html><head/><body><p style='white-space:pre'>Enable right-to-left reading.</p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Output split</string>
|
<string>Manga mode</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="2">
|
<item row="0" column="2">
|
||||||
<widget class="QCheckBox" name="colorBox">
|
<widget class="QCheckBox" name="qualityBox">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string><html><head/><body><p style='white-space:pre'>Disable conversion to grayscale.</p></body></html></string>
|
<string><html><head/><body><p style='white-space:pre'><span style=" font-weight:600; text-decoration: underline;">Unchecked - 4 panels<br/></span>Zoom each corner separately.</p><p style='white-space:pre'><span style=" font-weight:600; text-decoration: underline;">Indeterminate - 2 panels<br/></span>Zoom only the top and bottom of the page.</p><p><span style=" font-weight:600; text-decoration: underline;">Checked - 4 high-quality panels<br/></span>Zoom each corner separately. Try to increase the quality of magnification. Check wiki for more details.</p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Color mode</string>
|
<string>Panel View 4/2/HQ</string>
|
||||||
|
</property>
|
||||||
|
<property name="tristate">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0">
|
||||||
|
<widget class="QCheckBox" name="mozJpegBox">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><html><head/><body><p><span style=" font-weight:600; text-decoration: underline;">Unchecked - JPEG<br/></span>Use JPEG files</p><p><span style=" font-weight:600; text-decoration: underline;">Indeterminate - force PNG<br/></span>Create PNG files instead JPEG</p><p><span style=" font-weight:600; text-decoration: underline;">Checked - mozJpeg<br/></span>10-20% smaller JPEG file, with the same image quality, but processing time multiplied by 2</p></body></html></string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>JPEG/PNG/mozJpeg</string>
|
||||||
|
</property>
|
||||||
|
<property name="tristate">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="1">
|
||||||
|
<widget class="QCheckBox" name="maximizeStrips">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><html><head/><body><p><span style=" font-weight:600; text-decoration: underline;">Unchecked - 1x4<br/></span>Keep format 1x4 panels strips.</p><p><span style=" font-weight:600; text-decoration: underline;">Checked - 2x2<br/></span>Turn 1x4 strips to 2x2 to maximize screen usage.</p></body></html></string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>1x4 to 2x2 strips</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="2">
|
||||||
|
<widget class="QCheckBox" name="croppingBox">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><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></string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Cropping mode</string>
|
||||||
|
</property>
|
||||||
|
<property name="tristate">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="2">
|
||||||
|
<widget class="QCheckBox" name="disableProcessingBox">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><html><head/><body><p style='white-space:pre'>Do not process any image, ignore profil and processing options</p></body></html></string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Disable processing</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="5" column="0" colspan="2">
|
<item row="6" column="0" colspan="2">
|
||||||
<widget class="QWidget" name="gammaWidget" native="true">
|
<widget class="QWidget" name="gammaWidget" native="true">
|
||||||
<property name="visible">
|
<property name="visible">
|
||||||
<bool>false</bool>
|
<bool>false</bool>
|
||||||
@@ -294,9 +229,12 @@
|
|||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="0" colspan="2">
|
<item row="8" column="0" colspan="2">
|
||||||
<widget class="QWidget" name="toolWidget" native="true">
|
<widget class="QWidget" name="croppingWidget" native="true">
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
<property name="visible">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||||
<property name="leftMargin">
|
<property name="leftMargin">
|
||||||
<number>0</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
@@ -310,39 +248,22 @@
|
|||||||
<number>0</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="editorButton">
|
<widget class="QLabel" name="croppingPowerLabel">
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>0</width>
|
|
||||||
<height>30</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Editor</string>
|
<string>Cropping power:</string>
|
||||||
</property>
|
|
||||||
<property name="toolTip">
|
|
||||||
<string><html><head/><body><p style='white-space:pre'>Shift+Click to edit directory.</p></body></html></string>
|
|
||||||
</property>
|
|
||||||
<property name="icon">
|
|
||||||
<iconset resource="KCC.qrc">
|
|
||||||
<normaloff>:/Other/icons/editor.png</normaloff>:/Other/icons/editor.png</iconset>
|
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="wikiButton">
|
<widget class="QSlider" name="croppingPowerSlider">
|
||||||
<property name="minimumSize">
|
<property name="maximum">
|
||||||
<size>
|
<number>10</number>
|
||||||
<width>0</width>
|
|
||||||
<height>30</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="singleStep">
|
||||||
<string>Wiki</string>
|
<number>1</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="icon">
|
<property name="orientation">
|
||||||
<iconset resource="KCC.qrc">
|
<enum>Qt::Horizontal</enum>
|
||||||
<normaloff>:/Other/icons/wiki.png</normaloff>:/Other/icons/wiki.png</iconset>
|
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@@ -421,9 +342,6 @@
|
|||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string><html><head/><body><p style='white-space:pre'>Target device.</p></body></html></string>
|
<string><html><head/><body><p style='white-space:pre'>Target device.</p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizeAdjustPolicy">
|
|
||||||
<enum>QComboBox::AdjustToMinimumContentsLength</enum>
|
|
||||||
</property>
|
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="3">
|
<item row="1" column="3">
|
||||||
@@ -437,9 +355,6 @@
|
|||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string><html><head/><body><p style='white-space:pre'>Output format.</p></body></html></string>
|
<string><html><head/><body><p style='white-space:pre'>Output format.</p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizeAdjustPolicy">
|
|
||||||
<enum>QComboBox::AdjustToMinimumContentsLength</enum>
|
|
||||||
</property>
|
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="2">
|
<item row="1" column="2">
|
||||||
@@ -452,7 +367,6 @@
|
|||||||
</property>
|
</property>
|
||||||
<property name="font">
|
<property name="font">
|
||||||
<font>
|
<font>
|
||||||
<weight>75</weight>
|
|
||||||
<bold>true</bold>
|
<bold>true</bold>
|
||||||
</font>
|
</font>
|
||||||
</property>
|
</property>
|
||||||
@@ -494,6 +408,171 @@
|
|||||||
<zorder>formatBox</zorder>
|
<zorder>formatBox</zorder>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="0" column="0" colspan="2">
|
||||||
|
<widget class="QWidget" name="toolWidget" native="true">
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="editorButton">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>30</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><html><head/><body><p style='white-space:pre'>Shift+Click to edit directory.</p></body></html></string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Editor</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="KCC.qrc">
|
||||||
|
<normaloff>:/Other/icons/editor.png</normaloff>:/Other/icons/editor.png</iconset>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="wikiButton">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>30</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Wiki</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="KCC.qrc">
|
||||||
|
<normaloff>:/Other/icons/wiki.png</normaloff>:/Other/icons/wiki.png</iconset>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0" colspan="2">
|
||||||
|
<widget class="QListWidget" name="jobList">
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">QListWidget#jobList {background:#ffffff;background-image:url(:/Other/icons/list_background.png);background-position:center center;background-repeat:no-repeat;color:rgb(0,0,0);}</string>
|
||||||
|
</property>
|
||||||
|
<property name="selectionMode">
|
||||||
|
<enum>QAbstractItemView::NoSelection</enum>
|
||||||
|
</property>
|
||||||
|
<property name="verticalScrollMode">
|
||||||
|
<enum>QAbstractItemView::ScrollPerPixel</enum>
|
||||||
|
</property>
|
||||||
|
<property name="horizontalScrollMode">
|
||||||
|
<enum>QAbstractItemView::ScrollPerPixel</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0" colspan="2">
|
||||||
|
<widget class="QProgressBar" name="progressBar">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>30</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="visible">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignJustify|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="7" column="0" colspan="2">
|
||||||
|
<widget class="QWidget" name="customWidget" native="true">
|
||||||
|
<property name="visible">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_3">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item row="0" column="2">
|
||||||
|
<widget class="QLabel" name="hLabel">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><html><head/><body><p style='white-space:pre'>Resolution of the target device.</p></body></html></string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Custom height:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QSpinBox" name="widthBox">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><html><head/><body><p style='white-space:pre'>Resolution of the target device.</p></body></html></string>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>2160</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="wLabel">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><html><head/><body><p style='white-space:pre'>Resolution of the target device.</p></body></html></string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Custom width:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="3">
|
||||||
|
<widget class="QSpinBox" name="heightBox">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><html><head/><body><p style='white-space:pre'>Resolution of the target device.</p></body></html></string>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>3840</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QStatusBar" name="statusBar">
|
<widget class="QStatusBar" name="statusBar">
|
||||||
@@ -518,12 +597,17 @@
|
|||||||
<tabstop>borderBox</tabstop>
|
<tabstop>borderBox</tabstop>
|
||||||
<tabstop>outputSplit</tabstop>
|
<tabstop>outputSplit</tabstop>
|
||||||
<tabstop>colorBox</tabstop>
|
<tabstop>colorBox</tabstop>
|
||||||
|
<tabstop>croppingBox</tabstop>
|
||||||
|
<tabstop>mozJpegBox</tabstop>
|
||||||
|
<tabstop>maximizeStrips</tabstop>
|
||||||
|
<tabstop>disableProcessingBox</tabstop>
|
||||||
<tabstop>editorButton</tabstop>
|
<tabstop>editorButton</tabstop>
|
||||||
<tabstop>wikiButton</tabstop>
|
<tabstop>wikiButton</tabstop>
|
||||||
<tabstop>jobList</tabstop>
|
<tabstop>jobList</tabstop>
|
||||||
<tabstop>gammaSlider</tabstop>
|
<tabstop>gammaSlider</tabstop>
|
||||||
<tabstop>widthBox</tabstop>
|
<tabstop>widthBox</tabstop>
|
||||||
<tabstop>heightBox</tabstop>
|
<tabstop>heightBox</tabstop>
|
||||||
|
<tabstop>croppingPowerSlider</tabstop>
|
||||||
</tabstops>
|
</tabstops>
|
||||||
<resources>
|
<resources>
|
||||||
<include location="KCC.qrc"/>
|
<include location="KCC.qrc"/>
|
||||||
|
|||||||
@@ -112,19 +112,6 @@
|
|||||||
<item row="6" column="1">
|
<item row="6" column="1">
|
||||||
<widget class="QLineEdit" name="coloristLine"/>
|
<widget class="QLineEdit" name="coloristLine"/>
|
||||||
</item>
|
</item>
|
||||||
<item row="7" column="0">
|
|
||||||
<widget class="QLabel" name="label_8">
|
|
||||||
<property name="text">
|
|
||||||
<string><html><head/><body><p><a href="https://github.com/ciromattia/kcc/wiki/Manga-Cover-Database-support"><span style=" text-decoration: underline; color:#0000ff;">MUid:</span></a></p></body></html></string>
|
|
||||||
</property>
|
|
||||||
<property name="openExternalLinks">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="7" column="1">
|
|
||||||
<widget class="QLineEdit" name="muidLine"/>
|
|
||||||
</item>
|
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
|||||||
BIN
icons/KFX.png
Normal file
BIN
icons/KFX.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.8 KiB |
@@ -2,7 +2,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
||||||
# Copyright (c) 2013-2018 Pawel Jastrzebski <pawelj@iosphe.re>
|
# Copyright (c) 2013-2019 Pawel Jastrzebski <pawelj@iosphe.re>
|
||||||
#
|
#
|
||||||
# Permission to use, copy, modify, and/or distribute this software for
|
# Permission to use, copy, modify, and/or distribute this software for
|
||||||
# any purpose with or without fee is hereby granted, provided that the
|
# any purpose with or without fee is hereby granted, provided that the
|
||||||
@@ -23,9 +23,10 @@ if sys.version_info[0] != 3:
|
|||||||
print('ERROR: This is Python 3 script!')
|
print('ERROR: This is Python 3 script!')
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
from multiprocessing import freeze_support
|
from multiprocessing import freeze_support, set_start_method
|
||||||
from kindlecomicconverter.startup import startC2E
|
from kindlecomicconverter.startup import startC2E
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
set_start_method('spawn')
|
||||||
freeze_support()
|
freeze_support()
|
||||||
startC2E()
|
startC2E()
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
||||||
# Copyright (c) 2013-2018 Pawel Jastrzebski <pawelj@iosphe.re>
|
# Copyright (c) 2013-2019 Pawel Jastrzebski <pawelj@iosphe.re>
|
||||||
#
|
#
|
||||||
# Permission to use, copy, modify, and/or distribute this software for
|
# Permission to use, copy, modify, and/or distribute this software for
|
||||||
# any purpose with or without fee is hereby granted, provided that the
|
# any purpose with or without fee is hereby granted, provided that the
|
||||||
@@ -23,9 +23,10 @@ if sys.version_info[0] != 3:
|
|||||||
print('ERROR: This is Python 3 script!')
|
print('ERROR: This is Python 3 script!')
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
from multiprocessing import freeze_support
|
from multiprocessing import freeze_support, set_start_method
|
||||||
from kindlecomicconverter.startup import startC2P
|
from kindlecomicconverter.startup import startC2P
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
set_start_method('spawn')
|
||||||
freeze_support()
|
freeze_support()
|
||||||
startC2P()
|
startC2P()
|
||||||
|
|||||||
8
kcc.iss
8
kcc.iss
@@ -1,5 +1,5 @@
|
|||||||
#define MyAppName "Kindle Comic Converter"
|
#define MyAppName "Kindle Comic Converter"
|
||||||
#define MyAppVersion "5.4.5"
|
#define MyAppVersion "5.5.2"
|
||||||
#define MyAppPublisher "Ciro Mattia Gonano, Paweł Jastrzębski"
|
#define MyAppPublisher "Ciro Mattia Gonano, Paweł Jastrzębski"
|
||||||
#define MyAppURL "http://kcc.iosphe.re/"
|
#define MyAppURL "http://kcc.iosphe.re/"
|
||||||
#define MyAppExeName "KCC.exe"
|
#define MyAppExeName "KCC.exe"
|
||||||
@@ -12,7 +12,7 @@ AppPublisher={#MyAppPublisher}
|
|||||||
AppPublisherURL={#MyAppURL}
|
AppPublisherURL={#MyAppURL}
|
||||||
AppSupportURL={#MyAppURL}
|
AppSupportURL={#MyAppURL}
|
||||||
AppUpdatesURL={#MyAppURL}
|
AppUpdatesURL={#MyAppURL}
|
||||||
AppCopyright=Copyright (C) 2012-2018 Ciro Mattia Gonano and Paweł Jastrzębski
|
AppCopyright=Copyright (C) 2012-2019 Ciro Mattia Gonano and Paweł Jastrzębski
|
||||||
ArchitecturesAllowed=x64
|
ArchitecturesAllowed=x64
|
||||||
DefaultDirName={pf}\{#MyAppName}
|
DefaultDirName={pf}\{#MyAppName}
|
||||||
DefaultGroupName={#MyAppName}
|
DefaultGroupName={#MyAppName}
|
||||||
@@ -47,8 +47,8 @@ Name: "CB7association"; Description: "CB7"; GroupDescription: "File associations
|
|||||||
Source: "dist\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion
|
Source: "dist\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion
|
||||||
Source: "LICENSE.txt"; DestDir: "{app}"; Flags: ignoreversion solidbreak
|
Source: "LICENSE.txt"; DestDir: "{app}"; Flags: ignoreversion solidbreak
|
||||||
Source: "other\windows\Additional-LICENSE.txt"; DestDir: "{app}"; Flags: ignoreversion
|
Source: "other\windows\Additional-LICENSE.txt"; DestDir: "{app}"; Flags: ignoreversion
|
||||||
Source: "other\windows\UnRAR.exe"; DestDir: "{app}"; Flags: ignoreversion
|
Source: "other\windows\7z.exe"; DestDir: "{app}"; Flags: ignoreversion
|
||||||
Source: "other\windows\7za.exe"; DestDir: "{app}"; Flags: ignoreversion
|
Source: "other\windows\7z.dll"; DestDir: "{app}"; Flags: ignoreversion
|
||||||
|
|
||||||
[Icons]
|
[Icons]
|
||||||
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
|
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
|
||||||
|
|||||||
23
kcc.py
23
kcc.py
@@ -2,7 +2,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
||||||
# Copyright (c) 2013-2018 Pawel Jastrzebski <pawelj@iosphe.re>
|
# Copyright (c) 2013-2019 Pawel Jastrzebski <pawelj@iosphe.re>
|
||||||
#
|
#
|
||||||
# Permission to use, copy, modify, and/or distribute this software for
|
# Permission to use, copy, modify, and/or distribute this software for
|
||||||
# any purpose with or without fee is hereby granted, provided that the
|
# any purpose with or without fee is hereby granted, provided that the
|
||||||
@@ -28,11 +28,11 @@ import os
|
|||||||
if sys.platform.startswith('darwin'):
|
if sys.platform.startswith('darwin'):
|
||||||
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.path.dirname(os.path.abspath(sys.executable)) + \
|
||||||
'/../Resources:/usr/local/bin:/usr/bin:/bin'
|
'/../Resources:/Applications/Kindle Comic Creator/Kindle Comic Creator.app/Contents/' \
|
||||||
os.system('defaults write com.kindlecomicconverter.KindleComicConverter ApplePersistenceIgnoreState YES')
|
'MacOS:/usr/local/bin:/usr/bin:/bin'
|
||||||
os.system('defaults write com.kindlecomicconverter.KindleComicConverter NSInitialToolTipDelay -int 1000')
|
os.chdir(os.path.dirname(os.path.abspath(sys.executable)) + '/../Resources')
|
||||||
else:
|
else:
|
||||||
os.environ['PATH'] = os.path.dirname(os.path.abspath(__file__)) + '/other/osx/:' + os.environ['PATH']
|
os.chdir(os.path.dirname(os.path.abspath(__file__)))
|
||||||
elif sys.platform.startswith('win'):
|
elif sys.platform.startswith('win'):
|
||||||
if getattr(sys, 'frozen', False):
|
if getattr(sys, 'frozen', False):
|
||||||
os.chdir(os.path.dirname(os.path.abspath(sys.executable)))
|
os.chdir(os.path.dirname(os.path.abspath(sys.executable)))
|
||||||
@@ -40,16 +40,17 @@ elif sys.platform.startswith('win'):
|
|||||||
os.environ['PATH'] = os.path.dirname(os.path.abspath(__file__)) + '/other/windows/;' + os.environ['PATH']
|
os.environ['PATH'] = os.path.dirname(os.path.abspath(__file__)) + '/other/windows/;' + os.environ['PATH']
|
||||||
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):
|
||||||
try:
|
# try:
|
||||||
import kindlecomicconverter.sentry
|
# import kindlecomicconverter.sentry
|
||||||
except ImportError:
|
# except ImportError:
|
||||||
pass
|
# pass
|
||||||
|
|
||||||
from multiprocessing import freeze_support
|
from multiprocessing import freeze_support, set_start_method
|
||||||
from kindlecomicconverter.startup import start
|
from kindlecomicconverter.startup import start
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
set_start_method('spawn')
|
||||||
freeze_support()
|
freeze_support()
|
||||||
start()
|
start()
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
||||||
# Copyright (c) 2013-2018 Pawel Jastrzebski <pawelj@iosphe.re>
|
# Copyright (c) 2013-2019 Pawel Jastrzebski <pawelj@iosphe.re>
|
||||||
#
|
#
|
||||||
# Permission to use, copy, modify, and/or distribute this software for
|
# Permission to use, copy, modify, and/or distribute this software for
|
||||||
# any purpose with or without fee is hereby granted, provided that the
|
# any purpose with or without fee is hereby granted, provided that the
|
||||||
@@ -20,18 +20,19 @@
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
from urllib.parse import unquote
|
from urllib.parse import unquote
|
||||||
from urllib.request import urlopen, urlretrieve, Request
|
from urllib.request import urlretrieve
|
||||||
from time import sleep
|
from time import sleep
|
||||||
from shutil import move
|
from shutil import move, rmtree
|
||||||
from subprocess import STDOUT, PIPE
|
from subprocess import STDOUT, PIPE
|
||||||
|
# noinspection PyUnresolvedReferences
|
||||||
from PyQt5 import QtGui, QtCore, QtWidgets, QtNetwork
|
from PyQt5 import QtGui, QtCore, QtWidgets, QtNetwork
|
||||||
from xml.dom.minidom import parse
|
|
||||||
from xml.sax.saxutils import escape
|
from xml.sax.saxutils import escape
|
||||||
from psutil import Popen, Process
|
from psutil import Popen, Process
|
||||||
from copy import copy
|
from copy import copy
|
||||||
from distutils.version import StrictVersion
|
from distutils.version import StrictVersion
|
||||||
from raven import Client
|
from raven import Client
|
||||||
from .shared import md5Checksum, HTMLStripper, sanitizeTrace
|
from tempfile import gettempdir
|
||||||
|
from .shared import md5Checksum, HTMLStripper, sanitizeTrace, walkLevel
|
||||||
from . import __version__
|
from . import __version__
|
||||||
from . import comic2ebook
|
from . import comic2ebook
|
||||||
from . import metadata
|
from . import metadata
|
||||||
@@ -111,6 +112,12 @@ 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)
|
||||||
@@ -135,26 +142,31 @@ class VersionThread(QtCore.QThread):
|
|||||||
self.wait()
|
self.wait()
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
try:
|
# TODO adapt with github releases
|
||||||
XML = parse(urlopen(Request('https://kcc.iosphe.re/Version/',
|
pass
|
||||||
headers={'User-Agent': 'KindleComicConverter/' + __version__})))
|
|
||||||
except Exception:
|
# try:
|
||||||
return
|
# XML = parse(urlopen(Request('https://kcc.iosphe.re/Version/',
|
||||||
latestVersion = XML.childNodes[0].getElementsByTagName('LatestVersion')[0].childNodes[0].toxml()
|
# headers={'User-Agent': 'KindleComicConverter/' + __version__})))
|
||||||
if StrictVersion(latestVersion) > StrictVersion(__version__):
|
# except Exception:
|
||||||
if sys.platform.startswith('win'):
|
# return
|
||||||
self.newVersion = latestVersion
|
# latestVersion = XML.childNodes[0].getElementsByTagName('LatestVersion')[0].childNodes[0].toxml()
|
||||||
self.md5 = XML.childNodes[0].getElementsByTagName('MD5')[0].childNodes[0].toxml()
|
# if ("beta" not in __version__ and StrictVersion(latestVersion) > StrictVersion(__version__)) \
|
||||||
MW.showDialog.emit('<b>New version released!</b> <a href="https://github.com/ciromattia/kcc/releases/">'
|
# or ("beta" in __version__
|
||||||
'See changelog.</a><br/><br/>Installed version: ' + __version__ +
|
# and StrictVersion(latestVersion) >= StrictVersion(re.sub(r'-beta.*', '', __version__))):
|
||||||
'<br/>Current version: ' + latestVersion +
|
# if sys.platform.startswith('win'):
|
||||||
'<br/><br/>Would you like to start automatic update?', 'question')
|
# self.newVersion = latestVersion
|
||||||
self.getNewVersion()
|
# self.md5 = XML.childNodes[0].getElementsByTagName('MD5')[0].childNodes[0].toxml()
|
||||||
else:
|
# MW.showDialog.emit('<b>New version released!</b> <a href="https://github.com/ciromattia/kcc/releases/">'
|
||||||
MW.addMessage.emit('<a href="https://kcc.iosphe.re/">'
|
# 'See changelog.</a><br/><br/>Installed version: ' + __version__ +
|
||||||
'<b>The new version is available!</b></a> '
|
# '<br/>Current version: ' + latestVersion +
|
||||||
'(<a href="https://github.com/ciromattia/kcc/releases/">'
|
# '<br/><br/>Would you like to start automatic update?', 'question')
|
||||||
'Changelog</a>)', 'warning', False)
|
# 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
|
||||||
@@ -238,6 +250,7 @@ class WorkerThread(QtCore.QThread):
|
|||||||
MW.addTrayMessage.emit('Conversion interrupted.', 'Critical')
|
MW.addTrayMessage.emit('Conversion interrupted.', 'Critical')
|
||||||
MW.modeConvert.emit(1)
|
MW.modeConvert.emit(1)
|
||||||
|
|
||||||
|
# noinspection PyUnboundLocalVariable
|
||||||
def run(self):
|
def run(self):
|
||||||
MW.modeConvert.emit(0)
|
MW.modeConvert.emit(0)
|
||||||
|
|
||||||
@@ -266,6 +279,9 @@ class WorkerThread(QtCore.QThread):
|
|||||||
options.upscale = True
|
options.upscale = True
|
||||||
if GUI.gammaBox.isChecked() and float(GUI.gammaValue) > 0.09:
|
if GUI.gammaBox.isChecked() and float(GUI.gammaValue) > 0.09:
|
||||||
options.gamma = float(GUI.gammaValue)
|
options.gamma = float(GUI.gammaValue)
|
||||||
|
options.cropping = GUI.croppingBox.checkState()
|
||||||
|
if GUI.croppingBox.checkState() >= 1:
|
||||||
|
options.croppingp = float(GUI.croppingPowerValue)
|
||||||
if GUI.borderBox.checkState() == 1:
|
if GUI.borderBox.checkState() == 1:
|
||||||
options.white_borders = True
|
options.white_borders = True
|
||||||
elif GUI.borderBox.checkState() == 2:
|
elif GUI.borderBox.checkState() == 2:
|
||||||
@@ -274,6 +290,14 @@ class WorkerThread(QtCore.QThread):
|
|||||||
options.batchsplit = 2
|
options.batchsplit = 2
|
||||||
if GUI.colorBox.isChecked():
|
if GUI.colorBox.isChecked():
|
||||||
options.forcecolor = True
|
options.forcecolor = True
|
||||||
|
if GUI.maximizeStrips.isChecked():
|
||||||
|
options.maximizestrips = True
|
||||||
|
if GUI.disableProcessingBox.isChecked():
|
||||||
|
options.noprocessing = True
|
||||||
|
if GUI.mozJpegBox.checkState() == 1:
|
||||||
|
options.forcepng = True
|
||||||
|
elif GUI.mozJpegBox.checkState() == 2:
|
||||||
|
options.mozjpeg = True
|
||||||
if GUI.currentMode > 2:
|
if GUI.currentMode > 2:
|
||||||
options.customwidth = str(GUI.widthBox.value())
|
options.customwidth = str(GUI.widthBox.value())
|
||||||
options.customheight = str(GUI.heightBox.value())
|
options.customheight = str(GUI.heightBox.value())
|
||||||
@@ -299,8 +323,7 @@ class WorkerThread(QtCore.QThread):
|
|||||||
jobargv = list(argv)
|
jobargv = list(argv)
|
||||||
jobargv.append(job)
|
jobargv.append(job)
|
||||||
try:
|
try:
|
||||||
comic2ebook.options = copy(options)
|
comic2ebook.options = comic2ebook.checkOptions(copy(options))
|
||||||
comic2ebook.checkOptions()
|
|
||||||
outputPath = comic2ebook.makeBook(job, self)
|
outputPath = comic2ebook.makeBook(job, self)
|
||||||
MW.hideProgressBar.emit()
|
MW.hideProgressBar.emit()
|
||||||
except UserWarning as warn:
|
except UserWarning as warn:
|
||||||
@@ -345,7 +368,7 @@ class WorkerThread(QtCore.QThread):
|
|||||||
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':
|
if str(GUI.formatBox.currentText()) == 'MOBI/AZW3' or str(GUI.formatBox.currentText()) == 'MOBI+EPUB':
|
||||||
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')
|
||||||
@@ -477,20 +500,11 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
if self.needClean:
|
if self.needClean:
|
||||||
self.needClean = False
|
self.needClean = False
|
||||||
GUI.jobList.clear()
|
GUI.jobList.clear()
|
||||||
if self.UnRAR:
|
if self.sevenzip:
|
||||||
if self.sevenza:
|
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)')
|
|
||||||
else:
|
|
||||||
fnames = QtWidgets.QFileDialog.getOpenFileNames(MW, 'Select file', self.lastPath,
|
|
||||||
'Comic (*.cbz *.cbr *.zip *.rar *.pdf)')
|
|
||||||
else:
|
else:
|
||||||
if self.sevenza:
|
fnames = QtWidgets.QFileDialog.getOpenFileNames(MW, 'Select file', self.lastPath, 'Comic (*.pdf);;All (*.*)')
|
||||||
fnames = QtWidgets.QFileDialog.getOpenFileNames(MW, 'Select file', self.lastPath,
|
|
||||||
'Comic (*.cbz *.cb7 *.zip *.7z *.pdf)')
|
|
||||||
else:
|
|
||||||
fnames = QtWidgets.QFileDialog.getOpenFileNames(MW, 'Select file', self.lastPath,
|
|
||||||
'Comic (*.cbz *.zip *.pdf)')
|
|
||||||
for fname in fnames[0]:
|
for fname in fnames[0]:
|
||||||
if fname != '':
|
if fname != '':
|
||||||
if sys.platform.startswith('win'):
|
if sys.platform.startswith('win'):
|
||||||
@@ -509,20 +523,12 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
sname = sname.replace('/', '\\')
|
sname = sname.replace('/', '\\')
|
||||||
self.lastPath = os.path.abspath(sname)
|
self.lastPath = os.path.abspath(sname)
|
||||||
else:
|
else:
|
||||||
if self.UnRAR:
|
if self.sevenzip:
|
||||||
if self.sevenza:
|
fname = QtWidgets.QFileDialog.getOpenFileName(MW, 'Select file', self.lastPath,
|
||||||
fname = QtWidgets.QFileDialog.getOpenFileName(MW, 'Select file', self.lastPath,
|
'Comic (*.cbz *.cbr *.cb7)')
|
||||||
'Comic (*.cbz *.cbr *.cb7)')
|
|
||||||
else:
|
|
||||||
fname = QtWidgets.QFileDialog.getOpenFileName(MW, 'Select file', self.lastPath,
|
|
||||||
'Comic (*.cbz *.cbr)')
|
|
||||||
else:
|
else:
|
||||||
if self.sevenza:
|
fname = ['']
|
||||||
fname = QtWidgets.QFileDialog.getOpenFileName(MW, 'Select file', self.lastPath,
|
self.showDialog("Editor is disabled due to a lack of 7z.", 'error')
|
||||||
'Comic (*.cbz *.cb7)')
|
|
||||||
else:
|
|
||||||
fname = QtWidgets.QFileDialog.getOpenFileName(MW, 'Select file', self.lastPath,
|
|
||||||
'Comic (*.cbz)')
|
|
||||||
if fname[0] != '':
|
if fname[0] != '':
|
||||||
if sys.platform.startswith('win'):
|
if sys.platform.startswith('win'):
|
||||||
sname = fname[0].replace('/', '\\')
|
sname = fname[0].replace('/', '\\')
|
||||||
@@ -607,6 +613,13 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
if self.currentMode != 3:
|
if self.currentMode != 3:
|
||||||
self.modeChange(1)
|
self.modeChange(1)
|
||||||
|
|
||||||
|
def togglecroppingBox(self, value):
|
||||||
|
if value:
|
||||||
|
GUI.croppingWidget.setVisible(True)
|
||||||
|
else:
|
||||||
|
GUI.croppingWidget.setVisible(False)
|
||||||
|
self.changeCroppingPower(100) # 1.0
|
||||||
|
|
||||||
def togglewebtoonBox(self, value):
|
def togglewebtoonBox(self, value):
|
||||||
if value:
|
if value:
|
||||||
GUI.qualityBox.setEnabled(False)
|
GUI.qualityBox.setEnabled(False)
|
||||||
@@ -647,6 +660,13 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
GUI.gammaSlider.setValue(valueRaw)
|
GUI.gammaSlider.setValue(valueRaw)
|
||||||
self.gammaValue = value
|
self.gammaValue = value
|
||||||
|
|
||||||
|
def changeCroppingPower(self, value):
|
||||||
|
valueRaw = int(5 * round(float(value) / 5))
|
||||||
|
value = '%.2f' % (float(valueRaw) / 100)
|
||||||
|
GUI.croppingPowerLabel.setText('Cropping Power: ' + str(value))
|
||||||
|
GUI.croppingPowerSlider.setValue(valueRaw)
|
||||||
|
self.croppingPowerValue = value
|
||||||
|
|
||||||
def changeDevice(self):
|
def changeDevice(self):
|
||||||
profile = GUI.profiles[str(GUI.deviceBox.currentText())]
|
profile = GUI.profiles[str(GUI.deviceBox.currentText())]
|
||||||
if profile['ForceExpert']:
|
if profile['ForceExpert']:
|
||||||
@@ -792,13 +812,18 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
'rotateBox': GUI.rotateBox.checkState(),
|
'rotateBox': GUI.rotateBox.checkState(),
|
||||||
'qualityBox': GUI.qualityBox.checkState(),
|
'qualityBox': GUI.qualityBox.checkState(),
|
||||||
'gammaBox': GUI.gammaBox.checkState(),
|
'gammaBox': GUI.gammaBox.checkState(),
|
||||||
|
'croppingBox': GUI.croppingBox.checkState(),
|
||||||
|
'croppingPowerSlider': float(self.croppingPowerValue) * 100,
|
||||||
'upscaleBox': GUI.upscaleBox.checkState(),
|
'upscaleBox': GUI.upscaleBox.checkState(),
|
||||||
'borderBox': GUI.borderBox.checkState(),
|
'borderBox': GUI.borderBox.checkState(),
|
||||||
'webtoonBox': GUI.webtoonBox.checkState(),
|
'webtoonBox': GUI.webtoonBox.checkState(),
|
||||||
'outputSplit': GUI.outputSplit.checkState(),
|
'outputSplit': GUI.outputSplit.checkState(),
|
||||||
'colorBox': GUI.colorBox.checkState(),
|
'colorBox': GUI.colorBox.checkState(),
|
||||||
|
'disableProcessingBox': GUI.disableProcessingBox.checkState(),
|
||||||
|
'mozJpegBox': GUI.mozJpegBox.checkState(),
|
||||||
'widthBox': GUI.widthBox.value(),
|
'widthBox': GUI.widthBox.value(),
|
||||||
'heightBox': GUI.heightBox.value(),
|
'heightBox': GUI.heightBox.value(),
|
||||||
|
'maximizeStrips': GUI.maximizeStrips.checkState(),
|
||||||
'gammaSlider': float(self.gammaValue) * 100})
|
'gammaSlider': float(self.gammaValue) * 100})
|
||||||
self.settings.sync()
|
self.settings.sync()
|
||||||
self.tray.hide()
|
self.tray.hide()
|
||||||
@@ -812,16 +837,9 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
if self.needClean:
|
if self.needClean:
|
||||||
self.needClean = False
|
self.needClean = False
|
||||||
GUI.jobList.clear()
|
GUI.jobList.clear()
|
||||||
if self.UnRAR:
|
formats = ['.pdf']
|
||||||
if self.sevenza:
|
if self.sevenzip:
|
||||||
formats = ['.cbz', '.cbr', '.cb7', '.zip', '.rar', '.7z', '.pdf']
|
formats.extend(['.cb7', '.7z', '.cbz', '.zip', '.cbr', '.rar'])
|
||||||
else:
|
|
||||||
formats = ['.cbz', '.cbr', '.zip', '.rar', '.pdf']
|
|
||||||
else:
|
|
||||||
if self.sevenza:
|
|
||||||
formats = ['.cbz', '.cb7', '.zip', '.7z', '.pdf']
|
|
||||||
else:
|
|
||||||
formats = ['.cbz', '.zip', '.pdf']
|
|
||||||
if os.path.isdir(message):
|
if os.path.isdir(message):
|
||||||
GUI.jobList.addItem(message)
|
GUI.jobList.addItem(message)
|
||||||
GUI.jobList.scrollToBottom()
|
GUI.jobList.scrollToBottom()
|
||||||
@@ -831,7 +849,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
GUI.jobList.addItem(message)
|
GUI.jobList.addItem(message)
|
||||||
GUI.jobList.scrollToBottom()
|
GUI.jobList.scrollToBottom()
|
||||||
else:
|
else:
|
||||||
self.addMessage('This file type is unsupported!', 'error')
|
self.addMessage('Unsupported file type for ' + message, 'error')
|
||||||
|
|
||||||
def dragAndDrop(self, e):
|
def dragAndDrop(self, e):
|
||||||
e.accept()
|
e.accept()
|
||||||
@@ -858,7 +876,8 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
kindleGenExitCode = Popen('kindlegen -locale en', stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=True)
|
kindleGenExitCode = Popen('kindlegen -locale en', stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=True)
|
||||||
if kindleGenExitCode.wait() == 0:
|
kindleGenExitCode.communicate()
|
||||||
|
if kindleGenExitCode.returncode == 0:
|
||||||
self.kindleGen = True
|
self.kindleGen = True
|
||||||
versionCheck = Popen('kindlegen -locale en', stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=True)
|
versionCheck = Popen('kindlegen -locale en', stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=True)
|
||||||
for line in versionCheck.stdout:
|
for line in versionCheck.stdout:
|
||||||
@@ -877,7 +896,8 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
if sys.platform.startswith('win'):
|
if sys.platform.startswith('win'):
|
||||||
self.addMessage('Download it and place EXE in KCC directory.', 'error')
|
self.addMessage('Download it and place EXE in KCC directory.', 'error')
|
||||||
elif sys.platform.startswith('darwin'):
|
elif sys.platform.startswith('darwin'):
|
||||||
self.addMessage('Install it using <a href="http://brew.sh/">Brew</a>.', 'error')
|
self.addMessage('Install it using <a href="http://brew.sh/">Brew</a>: <i>brew cask install kindle-c'
|
||||||
|
'omic-creator</i>', 'error')
|
||||||
else:
|
else:
|
||||||
self.addMessage('Download it and place executable in /usr/local/bin directory.', 'error')
|
self.addMessage('Download it and place executable in /usr/local/bin directory.', 'error')
|
||||||
|
|
||||||
@@ -896,7 +916,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
self.currentFormat = self.settings.value('currentFormat', 0, type=int)
|
self.currentFormat = self.settings.value('currentFormat', 0, type=int)
|
||||||
self.startNumber = self.settings.value('startNumber', 0, type=int)
|
self.startNumber = self.settings.value('startNumber', 0, type=int)
|
||||||
self.windowSize = self.settings.value('windowSize', '0x0', type=str)
|
self.windowSize = self.settings.value('windowSize', '0x0', type=str)
|
||||||
self.options = self.settings.value('options', {'gammaSlider': 0})
|
self.options = self.settings.value('options', {'gammaSlider': 0, 'croppingBox': 2, 'croppingPowerSlider': 100})
|
||||||
self.worker = WorkerThread()
|
self.worker = WorkerThread()
|
||||||
self.versionCheck = VersionThread()
|
self.versionCheck = VersionThread()
|
||||||
self.progress = ProgressThread()
|
self.progress = ProgressThread()
|
||||||
@@ -905,10 +925,12 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
self.needClean = True
|
self.needClean = True
|
||||||
self.kindleGen = False
|
self.kindleGen = False
|
||||||
self.gammaValue = 1.0
|
self.gammaValue = 1.0
|
||||||
|
self.croppingPowerValue = 1.0
|
||||||
self.currentMode = 1
|
self.currentMode = 1
|
||||||
self.targetDirectory = ''
|
self.targetDirectory = ''
|
||||||
self.sentry = Client(release=__version__)
|
self.sentry = Client(release=__version__)
|
||||||
if sys.platform.startswith('win'):
|
if sys.platform.startswith('win'):
|
||||||
|
# noinspection PyUnresolvedReferences
|
||||||
from psutil import BELOW_NORMAL_PRIORITY_CLASS
|
from psutil import BELOW_NORMAL_PRIORITY_CLASS
|
||||||
self.p = Process(os.getpid())
|
self.p = Process(os.getpid())
|
||||||
self.p.nice(BELOW_NORMAL_PRIORITY_CLASS)
|
self.p.nice(BELOW_NORMAL_PRIORITY_CLASS)
|
||||||
@@ -928,14 +950,23 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
MW.resize(500, 500)
|
MW.resize(500, 500)
|
||||||
|
|
||||||
self.profiles = {
|
self.profiles = {
|
||||||
"Kindle Oasis 2": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
"Kindle Oasis 2/3": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
||||||
'DefaultUpscale': True, 'Label': 'KO'},
|
'DefaultUpscale': True, 'Label': 'KO'},
|
||||||
"Kindle Oasis": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
"Kindle Oasis": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
||||||
'DefaultUpscale': True, 'Label': 'KV'},
|
'DefaultUpscale': True, 'Label': 'KV'},
|
||||||
"Kindle Voyage": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
"Kindle Voyage": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
||||||
'DefaultUpscale': True, 'Label': 'KV'},
|
'DefaultUpscale': True, 'Label': 'KV'},
|
||||||
"Kindle PW 3": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
"Kindle Scribe": {
|
||||||
'DefaultUpscale': True, 'Label': 'KV'},
|
'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0, 'DefaultUpscale': True, 'Label': 'KS',
|
||||||
|
},
|
||||||
|
"Kindle 11": {
|
||||||
|
'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0, 'DefaultUpscale': True, 'Label': 'K11',
|
||||||
|
},
|
||||||
|
"Kindle PW 5": {
|
||||||
|
'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0, 'DefaultUpscale': True, 'Label': 'KPW5',
|
||||||
|
},
|
||||||
|
"Kindle PW 3/4": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
||||||
|
'DefaultUpscale': True, 'Label': 'KV'},
|
||||||
"Kindle PW 1/2": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
"Kindle PW 1/2": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
||||||
'DefaultUpscale': False, 'Label': 'KPW'},
|
'DefaultUpscale': False, 'Label': 'KPW'},
|
||||||
"Kindle": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
"Kindle": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
||||||
@@ -956,8 +987,12 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
'DefaultUpscale': True, 'Label': 'KoAH2O'},
|
'DefaultUpscale': True, 'Label': 'KoAH2O'},
|
||||||
"Kobo Aura ONE": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1,
|
"Kobo Aura ONE": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1,
|
||||||
'DefaultUpscale': True, 'Label': 'KoAO'},
|
'DefaultUpscale': True, 'Label': 'KoAO'},
|
||||||
"Other": {'PVOptions': False, 'ForceExpert': True, 'DefaultFormat': 1,
|
"Kobo Clara HD": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1,
|
||||||
'DefaultUpscale': False, 'Label': 'OTHER'},
|
'DefaultUpscale': True, 'Label': 'KoC'},
|
||||||
|
"Kobo Libra H2O": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1,
|
||||||
|
'DefaultUpscale': True, 'Label': 'KoL'},
|
||||||
|
"Kobo Forma": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1,
|
||||||
|
'DefaultUpscale': True, 'Label': 'KoF'},
|
||||||
"Kindle 1": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 0,
|
"Kindle 1": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 0,
|
||||||
'DefaultUpscale': False, 'Label': 'K1'},
|
'DefaultUpscale': False, 'Label': 'K1'},
|
||||||
"Kindle 2": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 0,
|
"Kindle 2": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 0,
|
||||||
@@ -966,30 +1001,53 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
'DefaultUpscale': False, 'Label': 'K34'},
|
'DefaultUpscale': False, 'Label': 'K34'},
|
||||||
"Kindle Touch": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 0,
|
"Kindle Touch": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 0,
|
||||||
'DefaultUpscale': False, 'Label': 'K34'},
|
'DefaultUpscale': False, 'Label': 'K34'},
|
||||||
|
"Kobo Nia": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1, 'DefaultUpscale': True,
|
||||||
|
'Label': 'KoN'},
|
||||||
|
"Kobo Clara 2E": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1, 'DefaultUpscale': True,
|
||||||
|
'Label': 'KoC'},
|
||||||
|
"Kobo Libra 2": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1, 'DefaultUpscale': True,
|
||||||
|
'Label': 'KoL'},
|
||||||
|
"Kobo Sage": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1, 'DefaultUpscale': True,
|
||||||
|
'Label': 'KoS'},
|
||||||
|
"Kobo Elipsa": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1, 'DefaultUpscale': True,
|
||||||
|
'Label': 'KoE'},
|
||||||
|
"Other": {'PVOptions': False, 'ForceExpert': True, 'DefaultFormat': 1, 'DefaultUpscale': False,
|
||||||
|
'Label': 'OTHER'},
|
||||||
}
|
}
|
||||||
profilesGUI = [
|
profilesGUI = [
|
||||||
"Kindle Oasis 2",
|
"Kindle Oasis 2/3",
|
||||||
"Kindle Oasis",
|
"Kindle PW 5",
|
||||||
"Kindle Voyage",
|
"Kindle 11",
|
||||||
"Kindle PW 3",
|
"Kindle Scribe",
|
||||||
"Kindle PW 1/2",
|
|
||||||
"Kindle",
|
|
||||||
"Separator",
|
"Separator",
|
||||||
"Kobo Aura ONE",
|
"Kobo Clara 2E",
|
||||||
"Kobo Aura H2O",
|
"Kobo Sage",
|
||||||
"Kobo Aura HD",
|
"Kobo Libra 2",
|
||||||
"Kobo Aura",
|
"Kobo Elipsa",
|
||||||
|
"Kobo Nia",
|
||||||
"Separator",
|
"Separator",
|
||||||
"Other",
|
"Other",
|
||||||
"Separator",
|
"Separator",
|
||||||
|
"Kindle Oasis",
|
||||||
"Kindle Touch",
|
"Kindle Touch",
|
||||||
"Kindle Keyboard",
|
"Kindle Keyboard",
|
||||||
"Kindle DX/DXG",
|
"Kindle DX/DXG",
|
||||||
|
"Kindle PW 3/4",
|
||||||
|
"Kindle PW 1/2",
|
||||||
|
"Kindle Voyage",
|
||||||
"Kindle 2",
|
"Kindle 2",
|
||||||
"Kindle 1",
|
"Kindle 1",
|
||||||
|
"Kindle",
|
||||||
"Separator",
|
"Separator",
|
||||||
|
"Kobo Aura",
|
||||||
|
"Kobo Aura ONE",
|
||||||
|
"Kobo Aura H2O",
|
||||||
|
"Kobo Aura HD",
|
||||||
|
"Kobo Clara HD",
|
||||||
|
"Kobo Forma",
|
||||||
"Kobo Glo HD",
|
"Kobo Glo HD",
|
||||||
"Kobo Glo",
|
"Kobo Glo",
|
||||||
|
"Kobo Libra H2O",
|
||||||
"Kobo Mini/Touch",
|
"Kobo Mini/Touch",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -1007,22 +1065,14 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
self.addMessage('Since you are a new user of <b>KCC</b> please see few '
|
self.addMessage('Since you are a new user of <b>KCC</b> please see few '
|
||||||
'<a href="https://github.com/ciromattia/kcc/wiki/Important-tips">important tips</a>.',
|
'<a href="https://github.com/ciromattia/kcc/wiki/Important-tips">important tips</a>.',
|
||||||
'info')
|
'info')
|
||||||
rarExitCode = Popen('unrar', stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=True)
|
process = Popen('7z', stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=True)
|
||||||
rarExitCode = rarExitCode.wait()
|
process.communicate()
|
||||||
if rarExitCode == 0 or rarExitCode == 1 or rarExitCode == 7:
|
if process.returncode == 0 or process.returncode == 7:
|
||||||
self.UnRAR = True
|
self.sevenzip = True
|
||||||
else:
|
else:
|
||||||
self.UnRAR = False
|
self.sevenzip = False
|
||||||
self.addMessage('Cannot find <a href="http://www.rarlab.com/rar_add.htm">UnRAR</a>!'
|
self.addMessage('Cannot find <a href="http://www.7-zip.org/download.html">7z</a>!'
|
||||||
' Processing of CBR/RAR files will be disabled.', 'warning')
|
' Processing of archives will be disabled.', 'warning')
|
||||||
sevenzaExitCode = Popen('7za', stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=True)
|
|
||||||
sevenzaExitCode = sevenzaExitCode.wait()
|
|
||||||
if sevenzaExitCode == 0 or sevenzaExitCode == 7:
|
|
||||||
self.sevenza = True
|
|
||||||
else:
|
|
||||||
self.sevenza = False
|
|
||||||
self.addMessage('Cannot find <a href="http://www.7-zip.org/download.html">7za</a>!'
|
|
||||||
' Processing of CB7/7Z files will be disabled.', 'warning')
|
|
||||||
self.detectKindleGen(True)
|
self.detectKindleGen(True)
|
||||||
|
|
||||||
APP.messageFromOtherInstance.connect(self.handleMessage)
|
APP.messageFromOtherInstance.connect(self.handleMessage)
|
||||||
@@ -1034,6 +1084,8 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
GUI.convertButton.clicked.connect(self.convertStart)
|
GUI.convertButton.clicked.connect(self.convertStart)
|
||||||
GUI.gammaSlider.valueChanged.connect(self.changeGamma)
|
GUI.gammaSlider.valueChanged.connect(self.changeGamma)
|
||||||
GUI.gammaBox.stateChanged.connect(self.togglegammaBox)
|
GUI.gammaBox.stateChanged.connect(self.togglegammaBox)
|
||||||
|
GUI.croppingBox.stateChanged.connect(self.togglecroppingBox)
|
||||||
|
GUI.croppingPowerSlider.valueChanged.connect(self.changeCroppingPower)
|
||||||
GUI.webtoonBox.stateChanged.connect(self.togglewebtoonBox)
|
GUI.webtoonBox.stateChanged.connect(self.togglewebtoonBox)
|
||||||
GUI.qualityBox.stateChanged.connect(self.togglequalityBox)
|
GUI.qualityBox.stateChanged.connect(self.togglequalityBox)
|
||||||
GUI.deviceBox.activated.connect(self.changeDevice)
|
GUI.deviceBox.activated.connect(self.changeDevice)
|
||||||
@@ -1061,8 +1113,9 @@ 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']:
|
for f in ['MOBI/AZW3', 'EPUB', 'CBZ', 'KFX', 'MOBI+EPUB', 'EPUB-200MB']:
|
||||||
GUI.formatBox.addItem(eval('self.icons.' + f.replace('/AZW3', '') + 'Format'), f)
|
format_prefix = f.replace('/AZW3', '').replace('+', '').replace('-', '')
|
||||||
|
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":
|
||||||
@@ -1082,6 +1135,10 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
if GUI.gammaSlider.isEnabled():
|
if GUI.gammaSlider.isEnabled():
|
||||||
GUI.gammaSlider.setValue(int(self.options[option]))
|
GUI.gammaSlider.setValue(int(self.options[option]))
|
||||||
self.changeGamma(int(self.options[option]))
|
self.changeGamma(int(self.options[option]))
|
||||||
|
elif str(option) == "croppingPowerSlider":
|
||||||
|
if GUI.croppingPowerSlider.isEnabled():
|
||||||
|
GUI.croppingPowerSlider.setValue(int(self.options[option]))
|
||||||
|
self.changeCroppingPower(int(self.options[option]))
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
if eval('GUI.' + str(option)).isEnabled():
|
if eval('GUI.' + str(option)).isEnabled():
|
||||||
@@ -1092,6 +1149,12 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
self.versionCheck.start()
|
self.versionCheck.start()
|
||||||
self.tray.show()
|
self.tray.show()
|
||||||
|
|
||||||
|
# Cleanup unfisnished conversion
|
||||||
|
for root, dirs, _ in walkLevel(gettempdir(), 0):
|
||||||
|
for tempdir in dirs:
|
||||||
|
if tempdir.startswith('KCC-'):
|
||||||
|
rmtree(os.path.join(root, tempdir), True)
|
||||||
|
|
||||||
if self.windowSize != '0x0':
|
if self.windowSize != '0x0':
|
||||||
x, y = self.windowSize.split('x')
|
x, y = self.windowSize.split('x')
|
||||||
MW.resize(int(x), int(y))
|
MW.resize(int(x), int(y))
|
||||||
@@ -1103,7 +1166,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
class KCCGUI_MetaEditor(KCC_ui_editor.Ui_editorDialog):
|
class KCCGUI_MetaEditor(KCC_ui_editor.Ui_editorDialog):
|
||||||
def loadData(self, file):
|
def loadData(self, file):
|
||||||
self.parser = metadata.MetadataParser(file)
|
self.parser = metadata.MetadataParser(file)
|
||||||
if self.parser.compressor == 'rar':
|
if self.parser.format in ['RAR', 'RAR5']:
|
||||||
self.editorWidget.setEnabled(False)
|
self.editorWidget.setEnabled(False)
|
||||||
self.okButton.setEnabled(False)
|
self.okButton.setEnabled(False)
|
||||||
self.statusLabel.setText('CBR metadata are read-only.')
|
self.statusLabel.setText('CBR metadata are read-only.')
|
||||||
@@ -1111,11 +1174,8 @@ class KCCGUI_MetaEditor(KCC_ui_editor.Ui_editorDialog):
|
|||||||
self.editorWidget.setEnabled(True)
|
self.editorWidget.setEnabled(True)
|
||||||
self.okButton.setEnabled(True)
|
self.okButton.setEnabled(True)
|
||||||
self.statusLabel.setText('Separate authors with a comma.')
|
self.statusLabel.setText('Separate authors with a comma.')
|
||||||
for field in (self.seriesLine, self.volumeLine, self.numberLine, self.muidLine):
|
for field in (self.seriesLine, self.volumeLine, self.numberLine):
|
||||||
if field.objectName() == 'muidLine':
|
field.setText(self.parser.data[field.objectName().capitalize()[:-4]])
|
||||||
field.setText(self.parser.data['MUid'])
|
|
||||||
else:
|
|
||||||
field.setText(self.parser.data[field.objectName().capitalize()[:-4]])
|
|
||||||
for field in (self.writerLine, self.pencillerLine, self.inkerLine, self.coloristLine):
|
for field in (self.writerLine, self.pencillerLine, self.inkerLine, self.coloristLine):
|
||||||
field.setText(', '.join(self.parser.data[field.objectName().capitalize()[:-4] + 's']))
|
field.setText(', '.join(self.parser.data[field.objectName().capitalize()[:-4] + 's']))
|
||||||
if self.seriesLine.text() == '':
|
if self.seriesLine.text() == '':
|
||||||
@@ -1125,12 +1185,9 @@ class KCCGUI_MetaEditor(KCC_ui_editor.Ui_editorDialog):
|
|||||||
self.seriesLine.setText(file.split('\\')[-1].split('/')[-1].split('.')[0])
|
self.seriesLine.setText(file.split('\\')[-1].split('/')[-1].split('.')[0])
|
||||||
|
|
||||||
def saveData(self):
|
def saveData(self):
|
||||||
for field in (self.volumeLine, self.numberLine, self.muidLine):
|
for field in (self.volumeLine, self.numberLine):
|
||||||
if field.text().isnumeric() or self.cleanData(field.text()) == '':
|
if field.text().isnumeric() or self.cleanData(field.text()) == '':
|
||||||
if field.objectName() == 'muidLine':
|
self.parser.data[field.objectName().capitalize()[:-4]] = self.cleanData(field.text())
|
||||||
self.parser.data['MUid'] = self.cleanData(field.text())
|
|
||||||
else:
|
|
||||||
self.parser.data[field.objectName().capitalize()[:-4]] = self.cleanData(field.text())
|
|
||||||
else:
|
else:
|
||||||
self.statusLabel.setText(field.objectName().capitalize()[:-4] + ' field must be a number.')
|
self.statusLabel.setText(field.objectName().capitalize()[:-4] + ' field must be a number.')
|
||||||
break
|
break
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,13 +1,16 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
# 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.8.1
|
# Created by: PyQt5 UI code generator 5.15.6
|
||||||
#
|
#
|
||||||
# WARNING! All changes made in this file will be lost!
|
# 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.
|
||||||
|
|
||||||
|
|
||||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
class Ui_mainWindow(object):
|
class Ui_mainWindow(object):
|
||||||
def setupUi(self, mainWindow):
|
def setupUi(self, mainWindow):
|
||||||
mainWindow.setObjectName("mainWindow")
|
mainWindow.setObjectName("mainWindow")
|
||||||
@@ -20,16 +23,165 @@ class Ui_mainWindow(object):
|
|||||||
self.gridLayout = QtWidgets.QGridLayout(self.centralWidget)
|
self.gridLayout = QtWidgets.QGridLayout(self.centralWidget)
|
||||||
self.gridLayout.setContentsMargins(-1, -1, -1, 5)
|
self.gridLayout.setContentsMargins(-1, -1, -1, 5)
|
||||||
self.gridLayout.setObjectName("gridLayout")
|
self.gridLayout.setObjectName("gridLayout")
|
||||||
self.progressBar = QtWidgets.QProgressBar(self.centralWidget)
|
self.optionWidget = QtWidgets.QWidget(self.centralWidget)
|
||||||
self.progressBar.setMinimumSize(QtCore.QSize(0, 30))
|
self.optionWidget.setObjectName("optionWidget")
|
||||||
|
self.gridLayout_2 = QtWidgets.QGridLayout(self.optionWidget)
|
||||||
|
self.gridLayout_2.setContentsMargins(0, 0, 0, 0)
|
||||||
|
self.gridLayout_2.setObjectName("gridLayout_2")
|
||||||
|
self.upscaleBox = QtWidgets.QCheckBox(self.optionWidget)
|
||||||
|
self.upscaleBox.setTristate(True)
|
||||||
|
self.upscaleBox.setObjectName("upscaleBox")
|
||||||
|
self.gridLayout_2.addWidget(self.upscaleBox, 1, 1, 1, 1)
|
||||||
|
self.rotateBox = QtWidgets.QCheckBox(self.optionWidget)
|
||||||
|
self.rotateBox.setTristate(True)
|
||||||
|
self.rotateBox.setObjectName("rotateBox")
|
||||||
|
self.gridLayout_2.addWidget(self.rotateBox, 0, 1, 1, 1)
|
||||||
|
self.outputSplit = QtWidgets.QCheckBox(self.optionWidget)
|
||||||
|
self.outputSplit.setObjectName("outputSplit")
|
||||||
|
self.gridLayout_2.addWidget(self.outputSplit, 2, 1, 1, 1)
|
||||||
|
self.webtoonBox = QtWidgets.QCheckBox(self.optionWidget)
|
||||||
|
self.webtoonBox.setObjectName("webtoonBox")
|
||||||
|
self.gridLayout_2.addWidget(self.webtoonBox, 1, 0, 1, 1)
|
||||||
|
self.colorBox = QtWidgets.QCheckBox(self.optionWidget)
|
||||||
|
self.colorBox.setObjectName("colorBox")
|
||||||
|
self.gridLayout_2.addWidget(self.colorBox, 2, 2, 1, 1)
|
||||||
|
self.gammaBox = QtWidgets.QCheckBox(self.optionWidget)
|
||||||
|
self.gammaBox.setObjectName("gammaBox")
|
||||||
|
self.gridLayout_2.addWidget(self.gammaBox, 1, 2, 1, 1)
|
||||||
|
self.borderBox = QtWidgets.QCheckBox(self.optionWidget)
|
||||||
|
self.borderBox.setTristate(True)
|
||||||
|
self.borderBox.setObjectName("borderBox")
|
||||||
|
self.gridLayout_2.addWidget(self.borderBox, 2, 0, 1, 1)
|
||||||
|
self.mangaBox = QtWidgets.QCheckBox(self.optionWidget)
|
||||||
|
self.mangaBox.setObjectName("mangaBox")
|
||||||
|
self.gridLayout_2.addWidget(self.mangaBox, 0, 0, 1, 1)
|
||||||
|
self.qualityBox = QtWidgets.QCheckBox(self.optionWidget)
|
||||||
|
self.qualityBox.setTristate(True)
|
||||||
|
self.qualityBox.setObjectName("qualityBox")
|
||||||
|
self.gridLayout_2.addWidget(self.qualityBox, 0, 2, 1, 1)
|
||||||
|
self.mozJpegBox = QtWidgets.QCheckBox(self.optionWidget)
|
||||||
|
self.mozJpegBox.setTristate(True)
|
||||||
|
self.mozJpegBox.setObjectName("mozJpegBox")
|
||||||
|
self.gridLayout_2.addWidget(self.mozJpegBox, 3, 0, 1, 1)
|
||||||
|
self.maximizeStrips = QtWidgets.QCheckBox(self.optionWidget)
|
||||||
|
self.maximizeStrips.setObjectName("maximizeStrips")
|
||||||
|
self.gridLayout_2.addWidget(self.maximizeStrips, 3, 1, 1, 1)
|
||||||
|
self.croppingBox = QtWidgets.QCheckBox(self.optionWidget)
|
||||||
|
self.croppingBox.setTristate(True)
|
||||||
|
self.croppingBox.setObjectName("croppingBox")
|
||||||
|
self.gridLayout_2.addWidget(self.croppingBox, 3, 2, 1, 1)
|
||||||
|
self.disableProcessingBox = QtWidgets.QCheckBox(self.optionWidget)
|
||||||
|
self.disableProcessingBox.setObjectName("disableProcessingBox")
|
||||||
|
self.gridLayout_2.addWidget(self.disableProcessingBox, 4, 2, 1, 1)
|
||||||
|
self.gridLayout.addWidget(self.optionWidget, 5, 0, 1, 2)
|
||||||
|
self.gammaWidget = QtWidgets.QWidget(self.centralWidget)
|
||||||
|
self.gammaWidget.setVisible(False)
|
||||||
|
self.gammaWidget.setObjectName("gammaWidget")
|
||||||
|
self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.gammaWidget)
|
||||||
|
self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0)
|
||||||
|
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
|
||||||
|
self.gammaLabel = QtWidgets.QLabel(self.gammaWidget)
|
||||||
|
self.gammaLabel.setObjectName("gammaLabel")
|
||||||
|
self.horizontalLayout_2.addWidget(self.gammaLabel)
|
||||||
|
self.gammaSlider = QtWidgets.QSlider(self.gammaWidget)
|
||||||
|
self.gammaSlider.setMaximum(250)
|
||||||
|
self.gammaSlider.setSingleStep(5)
|
||||||
|
self.gammaSlider.setOrientation(QtCore.Qt.Horizontal)
|
||||||
|
self.gammaSlider.setObjectName("gammaSlider")
|
||||||
|
self.horizontalLayout_2.addWidget(self.gammaSlider)
|
||||||
|
self.gridLayout.addWidget(self.gammaWidget, 6, 0, 1, 2)
|
||||||
|
self.croppingWidget = QtWidgets.QWidget(self.centralWidget)
|
||||||
|
self.croppingWidget.setVisible(False)
|
||||||
|
self.croppingWidget.setObjectName("croppingWidget")
|
||||||
|
self.horizontalLayout_3 = QtWidgets.QHBoxLayout(self.croppingWidget)
|
||||||
|
self.horizontalLayout_3.setContentsMargins(0, 0, 0, 0)
|
||||||
|
self.horizontalLayout_3.setObjectName("horizontalLayout_3")
|
||||||
|
self.croppingPowerLabel = QtWidgets.QLabel(self.croppingWidget)
|
||||||
|
self.croppingPowerLabel.setObjectName("croppingPowerLabel")
|
||||||
|
self.horizontalLayout_3.addWidget(self.croppingPowerLabel)
|
||||||
|
self.croppingPowerSlider = QtWidgets.QSlider(self.croppingWidget)
|
||||||
|
self.croppingPowerSlider.setMaximum(200)
|
||||||
|
self.croppingPowerSlider.setSingleStep(1)
|
||||||
|
self.croppingPowerSlider.setOrientation(QtCore.Qt.Horizontal)
|
||||||
|
self.croppingPowerSlider.setObjectName("croppingPowerSlider")
|
||||||
|
self.horizontalLayout_3.addWidget(self.croppingPowerSlider)
|
||||||
|
self.gridLayout.addWidget(self.croppingWidget, 8, 0, 1, 2)
|
||||||
|
self.buttonWidget = QtWidgets.QWidget(self.centralWidget)
|
||||||
|
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
|
||||||
|
sizePolicy.setHorizontalStretch(0)
|
||||||
|
sizePolicy.setVerticalStretch(0)
|
||||||
|
sizePolicy.setHeightForWidth(self.buttonWidget.sizePolicy().hasHeightForWidth())
|
||||||
|
self.buttonWidget.setSizePolicy(sizePolicy)
|
||||||
|
self.buttonWidget.setObjectName("buttonWidget")
|
||||||
|
self.gridLayout_4 = QtWidgets.QGridLayout(self.buttonWidget)
|
||||||
|
self.gridLayout_4.setContentsMargins(0, 0, 0, 0)
|
||||||
|
self.gridLayout_4.setObjectName("gridLayout_4")
|
||||||
|
self.directoryButton = QtWidgets.QPushButton(self.buttonWidget)
|
||||||
|
self.directoryButton.setMinimumSize(QtCore.QSize(0, 30))
|
||||||
|
icon1 = QtGui.QIcon()
|
||||||
|
icon1.addPixmap(QtGui.QPixmap(":/Other/icons/folder_new.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||||
|
self.directoryButton.setIcon(icon1)
|
||||||
|
self.directoryButton.setObjectName("directoryButton")
|
||||||
|
self.gridLayout_4.addWidget(self.directoryButton, 0, 0, 1, 1)
|
||||||
|
self.fileButton = QtWidgets.QPushButton(self.buttonWidget)
|
||||||
|
self.fileButton.setMinimumSize(QtCore.QSize(0, 30))
|
||||||
|
icon2 = QtGui.QIcon()
|
||||||
|
icon2.addPixmap(QtGui.QPixmap(":/Other/icons/document_new.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||||
|
self.fileButton.setIcon(icon2)
|
||||||
|
self.fileButton.setObjectName("fileButton")
|
||||||
|
self.gridLayout_4.addWidget(self.fileButton, 0, 3, 1, 1)
|
||||||
|
self.deviceBox = QtWidgets.QComboBox(self.buttonWidget)
|
||||||
|
self.deviceBox.setMinimumSize(QtCore.QSize(0, 28))
|
||||||
|
self.deviceBox.setObjectName("deviceBox")
|
||||||
|
self.gridLayout_4.addWidget(self.deviceBox, 1, 0, 1, 1)
|
||||||
|
self.formatBox = QtWidgets.QComboBox(self.buttonWidget)
|
||||||
|
self.formatBox.setMinimumSize(QtCore.QSize(0, 28))
|
||||||
|
self.formatBox.setObjectName("formatBox")
|
||||||
|
self.gridLayout_4.addWidget(self.formatBox, 1, 3, 1, 1)
|
||||||
|
self.convertButton = QtWidgets.QPushButton(self.buttonWidget)
|
||||||
|
self.convertButton.setMinimumSize(QtCore.QSize(0, 30))
|
||||||
font = QtGui.QFont()
|
font = QtGui.QFont()
|
||||||
font.setBold(True)
|
font.setBold(True)
|
||||||
font.setWeight(75)
|
self.convertButton.setFont(font)
|
||||||
self.progressBar.setFont(font)
|
icon3 = QtGui.QIcon()
|
||||||
self.progressBar.setVisible(False)
|
icon3.addPixmap(QtGui.QPixmap(":/Other/icons/convert.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||||
self.progressBar.setAlignment(QtCore.Qt.AlignJustify|QtCore.Qt.AlignVCenter)
|
self.convertButton.setIcon(icon3)
|
||||||
self.progressBar.setObjectName("progressBar")
|
self.convertButton.setObjectName("convertButton")
|
||||||
self.gridLayout.addWidget(self.progressBar, 1, 0, 1, 2)
|
self.gridLayout_4.addWidget(self.convertButton, 1, 2, 1, 1)
|
||||||
|
self.clearButton = QtWidgets.QPushButton(self.buttonWidget)
|
||||||
|
self.clearButton.setMinimumSize(QtCore.QSize(0, 30))
|
||||||
|
icon4 = QtGui.QIcon()
|
||||||
|
icon4.addPixmap(QtGui.QPixmap(":/Other/icons/clear.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||||
|
self.clearButton.setIcon(icon4)
|
||||||
|
self.clearButton.setObjectName("clearButton")
|
||||||
|
self.gridLayout_4.addWidget(self.clearButton, 0, 2, 1, 1)
|
||||||
|
self.directoryButton.raise_()
|
||||||
|
self.clearButton.raise_()
|
||||||
|
self.fileButton.raise_()
|
||||||
|
self.deviceBox.raise_()
|
||||||
|
self.convertButton.raise_()
|
||||||
|
self.formatBox.raise_()
|
||||||
|
self.gridLayout.addWidget(self.buttonWidget, 3, 0, 1, 2)
|
||||||
|
self.toolWidget = QtWidgets.QWidget(self.centralWidget)
|
||||||
|
self.toolWidget.setObjectName("toolWidget")
|
||||||
|
self.horizontalLayout = QtWidgets.QHBoxLayout(self.toolWidget)
|
||||||
|
self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
|
||||||
|
self.horizontalLayout.setObjectName("horizontalLayout")
|
||||||
|
self.editorButton = QtWidgets.QPushButton(self.toolWidget)
|
||||||
|
self.editorButton.setMinimumSize(QtCore.QSize(0, 30))
|
||||||
|
icon5 = QtGui.QIcon()
|
||||||
|
icon5.addPixmap(QtGui.QPixmap(":/Other/icons/editor.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||||
|
self.editorButton.setIcon(icon5)
|
||||||
|
self.editorButton.setObjectName("editorButton")
|
||||||
|
self.horizontalLayout.addWidget(self.editorButton)
|
||||||
|
self.wikiButton = QtWidgets.QPushButton(self.toolWidget)
|
||||||
|
self.wikiButton.setMinimumSize(QtCore.QSize(0, 30))
|
||||||
|
icon6 = QtGui.QIcon()
|
||||||
|
icon6.addPixmap(QtGui.QPixmap(":/Other/icons/wiki.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||||
|
self.wikiButton.setIcon(icon6)
|
||||||
|
self.wikiButton.setObjectName("wikiButton")
|
||||||
|
self.horizontalLayout.addWidget(self.wikiButton)
|
||||||
|
self.gridLayout.addWidget(self.toolWidget, 0, 0, 1, 2)
|
||||||
self.jobList = QtWidgets.QListWidget(self.centralWidget)
|
self.jobList = QtWidgets.QListWidget(self.centralWidget)
|
||||||
self.jobList.setStyleSheet("QListWidget#jobList {background:#ffffff;background-image:url(:/Other/icons/list_background.png);background-position:center center;background-repeat:no-repeat;color:rgb(0,0,0);}")
|
self.jobList.setStyleSheet("QListWidget#jobList {background:#ffffff;background-image:url(:/Other/icons/list_background.png);background-position:center center;background-repeat:no-repeat;color:rgb(0,0,0);}")
|
||||||
self.jobList.setSelectionMode(QtWidgets.QAbstractItemView.NoSelection)
|
self.jobList.setSelectionMode(QtWidgets.QAbstractItemView.NoSelection)
|
||||||
@@ -37,6 +189,15 @@ class Ui_mainWindow(object):
|
|||||||
self.jobList.setHorizontalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel)
|
self.jobList.setHorizontalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel)
|
||||||
self.jobList.setObjectName("jobList")
|
self.jobList.setObjectName("jobList")
|
||||||
self.gridLayout.addWidget(self.jobList, 2, 0, 1, 2)
|
self.gridLayout.addWidget(self.jobList, 2, 0, 1, 2)
|
||||||
|
self.progressBar = QtWidgets.QProgressBar(self.centralWidget)
|
||||||
|
self.progressBar.setMinimumSize(QtCore.QSize(0, 30))
|
||||||
|
font = QtGui.QFont()
|
||||||
|
font.setBold(True)
|
||||||
|
self.progressBar.setFont(font)
|
||||||
|
self.progressBar.setVisible(False)
|
||||||
|
self.progressBar.setAlignment(QtCore.Qt.AlignJustify|QtCore.Qt.AlignVCenter)
|
||||||
|
self.progressBar.setObjectName("progressBar")
|
||||||
|
self.gridLayout.addWidget(self.progressBar, 1, 0, 1, 2)
|
||||||
self.customWidget = QtWidgets.QWidget(self.centralWidget)
|
self.customWidget = QtWidgets.QWidget(self.centralWidget)
|
||||||
self.customWidget.setVisible(False)
|
self.customWidget.setVisible(False)
|
||||||
self.customWidget.setObjectName("customWidget")
|
self.customWidget.setObjectName("customWidget")
|
||||||
@@ -67,139 +228,7 @@ class Ui_mainWindow(object):
|
|||||||
self.heightBox.setMaximum(3840)
|
self.heightBox.setMaximum(3840)
|
||||||
self.heightBox.setObjectName("heightBox")
|
self.heightBox.setObjectName("heightBox")
|
||||||
self.gridLayout_3.addWidget(self.heightBox, 0, 3, 1, 1)
|
self.gridLayout_3.addWidget(self.heightBox, 0, 3, 1, 1)
|
||||||
self.gridLayout.addWidget(self.customWidget, 6, 0, 1, 2)
|
self.gridLayout.addWidget(self.customWidget, 7, 0, 1, 2)
|
||||||
self.optionWidget = QtWidgets.QWidget(self.centralWidget)
|
|
||||||
self.optionWidget.setObjectName("optionWidget")
|
|
||||||
self.gridLayout_2 = QtWidgets.QGridLayout(self.optionWidget)
|
|
||||||
self.gridLayout_2.setContentsMargins(0, 0, 0, 0)
|
|
||||||
self.gridLayout_2.setObjectName("gridLayout_2")
|
|
||||||
self.mangaBox = QtWidgets.QCheckBox(self.optionWidget)
|
|
||||||
self.mangaBox.setObjectName("mangaBox")
|
|
||||||
self.gridLayout_2.addWidget(self.mangaBox, 0, 0, 1, 1)
|
|
||||||
self.rotateBox = QtWidgets.QCheckBox(self.optionWidget)
|
|
||||||
self.rotateBox.setTristate(True)
|
|
||||||
self.rotateBox.setObjectName("rotateBox")
|
|
||||||
self.gridLayout_2.addWidget(self.rotateBox, 0, 1, 1, 1)
|
|
||||||
self.qualityBox = QtWidgets.QCheckBox(self.optionWidget)
|
|
||||||
self.qualityBox.setTristate(True)
|
|
||||||
self.qualityBox.setObjectName("qualityBox")
|
|
||||||
self.gridLayout_2.addWidget(self.qualityBox, 0, 2, 1, 1)
|
|
||||||
self.webtoonBox = QtWidgets.QCheckBox(self.optionWidget)
|
|
||||||
self.webtoonBox.setObjectName("webtoonBox")
|
|
||||||
self.gridLayout_2.addWidget(self.webtoonBox, 1, 0, 1, 1)
|
|
||||||
self.upscaleBox = QtWidgets.QCheckBox(self.optionWidget)
|
|
||||||
self.upscaleBox.setTristate(True)
|
|
||||||
self.upscaleBox.setObjectName("upscaleBox")
|
|
||||||
self.gridLayout_2.addWidget(self.upscaleBox, 1, 1, 1, 1)
|
|
||||||
self.gammaBox = QtWidgets.QCheckBox(self.optionWidget)
|
|
||||||
self.gammaBox.setObjectName("gammaBox")
|
|
||||||
self.gridLayout_2.addWidget(self.gammaBox, 1, 2, 1, 1)
|
|
||||||
self.borderBox = QtWidgets.QCheckBox(self.optionWidget)
|
|
||||||
self.borderBox.setTristate(True)
|
|
||||||
self.borderBox.setObjectName("borderBox")
|
|
||||||
self.gridLayout_2.addWidget(self.borderBox, 2, 0, 1, 1)
|
|
||||||
self.outputSplit = QtWidgets.QCheckBox(self.optionWidget)
|
|
||||||
self.outputSplit.setObjectName("outputSplit")
|
|
||||||
self.gridLayout_2.addWidget(self.outputSplit, 2, 1, 1, 1)
|
|
||||||
self.colorBox = QtWidgets.QCheckBox(self.optionWidget)
|
|
||||||
self.colorBox.setObjectName("colorBox")
|
|
||||||
self.gridLayout_2.addWidget(self.colorBox, 2, 2, 1, 1)
|
|
||||||
self.gridLayout.addWidget(self.optionWidget, 4, 0, 1, 2)
|
|
||||||
self.gammaWidget = QtWidgets.QWidget(self.centralWidget)
|
|
||||||
self.gammaWidget.setVisible(False)
|
|
||||||
self.gammaWidget.setObjectName("gammaWidget")
|
|
||||||
self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.gammaWidget)
|
|
||||||
self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0)
|
|
||||||
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
|
|
||||||
self.gammaLabel = QtWidgets.QLabel(self.gammaWidget)
|
|
||||||
self.gammaLabel.setObjectName("gammaLabel")
|
|
||||||
self.horizontalLayout_2.addWidget(self.gammaLabel)
|
|
||||||
self.gammaSlider = QtWidgets.QSlider(self.gammaWidget)
|
|
||||||
self.gammaSlider.setMaximum(250)
|
|
||||||
self.gammaSlider.setSingleStep(5)
|
|
||||||
self.gammaSlider.setOrientation(QtCore.Qt.Horizontal)
|
|
||||||
self.gammaSlider.setObjectName("gammaSlider")
|
|
||||||
self.horizontalLayout_2.addWidget(self.gammaSlider)
|
|
||||||
self.gridLayout.addWidget(self.gammaWidget, 5, 0, 1, 2)
|
|
||||||
self.toolWidget = QtWidgets.QWidget(self.centralWidget)
|
|
||||||
self.toolWidget.setObjectName("toolWidget")
|
|
||||||
self.horizontalLayout = QtWidgets.QHBoxLayout(self.toolWidget)
|
|
||||||
self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
|
|
||||||
self.horizontalLayout.setObjectName("horizontalLayout")
|
|
||||||
self.editorButton = QtWidgets.QPushButton(self.toolWidget)
|
|
||||||
self.editorButton.setMinimumSize(QtCore.QSize(0, 30))
|
|
||||||
icon1 = QtGui.QIcon()
|
|
||||||
icon1.addPixmap(QtGui.QPixmap(":/Other/icons/editor.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
|
||||||
self.editorButton.setIcon(icon1)
|
|
||||||
self.editorButton.setObjectName("editorButton")
|
|
||||||
self.horizontalLayout.addWidget(self.editorButton)
|
|
||||||
self.wikiButton = QtWidgets.QPushButton(self.toolWidget)
|
|
||||||
self.wikiButton.setMinimumSize(QtCore.QSize(0, 30))
|
|
||||||
icon2 = QtGui.QIcon()
|
|
||||||
icon2.addPixmap(QtGui.QPixmap(":/Other/icons/wiki.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
|
||||||
self.wikiButton.setIcon(icon2)
|
|
||||||
self.wikiButton.setObjectName("wikiButton")
|
|
||||||
self.horizontalLayout.addWidget(self.wikiButton)
|
|
||||||
self.gridLayout.addWidget(self.toolWidget, 0, 0, 1, 2)
|
|
||||||
self.buttonWidget = QtWidgets.QWidget(self.centralWidget)
|
|
||||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
|
|
||||||
sizePolicy.setHorizontalStretch(0)
|
|
||||||
sizePolicy.setVerticalStretch(0)
|
|
||||||
sizePolicy.setHeightForWidth(self.buttonWidget.sizePolicy().hasHeightForWidth())
|
|
||||||
self.buttonWidget.setSizePolicy(sizePolicy)
|
|
||||||
self.buttonWidget.setObjectName("buttonWidget")
|
|
||||||
self.gridLayout_4 = QtWidgets.QGridLayout(self.buttonWidget)
|
|
||||||
self.gridLayout_4.setContentsMargins(0, 0, 0, 0)
|
|
||||||
self.gridLayout_4.setObjectName("gridLayout_4")
|
|
||||||
self.directoryButton = QtWidgets.QPushButton(self.buttonWidget)
|
|
||||||
self.directoryButton.setMinimumSize(QtCore.QSize(0, 30))
|
|
||||||
icon3 = QtGui.QIcon()
|
|
||||||
icon3.addPixmap(QtGui.QPixmap(":/Other/icons/folder_new.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
|
||||||
self.directoryButton.setIcon(icon3)
|
|
||||||
self.directoryButton.setObjectName("directoryButton")
|
|
||||||
self.gridLayout_4.addWidget(self.directoryButton, 0, 0, 1, 1)
|
|
||||||
self.fileButton = QtWidgets.QPushButton(self.buttonWidget)
|
|
||||||
self.fileButton.setMinimumSize(QtCore.QSize(0, 30))
|
|
||||||
icon4 = QtGui.QIcon()
|
|
||||||
icon4.addPixmap(QtGui.QPixmap(":/Other/icons/document_new.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
|
||||||
self.fileButton.setIcon(icon4)
|
|
||||||
self.fileButton.setObjectName("fileButton")
|
|
||||||
self.gridLayout_4.addWidget(self.fileButton, 0, 3, 1, 1)
|
|
||||||
self.deviceBox = QtWidgets.QComboBox(self.buttonWidget)
|
|
||||||
self.deviceBox.setMinimumSize(QtCore.QSize(0, 28))
|
|
||||||
self.deviceBox.setSizeAdjustPolicy(QtWidgets.QComboBox.AdjustToMinimumContentsLength)
|
|
||||||
self.deviceBox.setObjectName("deviceBox")
|
|
||||||
self.gridLayout_4.addWidget(self.deviceBox, 1, 0, 1, 1)
|
|
||||||
self.formatBox = QtWidgets.QComboBox(self.buttonWidget)
|
|
||||||
self.formatBox.setMinimumSize(QtCore.QSize(0, 28))
|
|
||||||
self.formatBox.setSizeAdjustPolicy(QtWidgets.QComboBox.AdjustToMinimumContentsLength)
|
|
||||||
self.formatBox.setObjectName("formatBox")
|
|
||||||
self.gridLayout_4.addWidget(self.formatBox, 1, 3, 1, 1)
|
|
||||||
self.convertButton = QtWidgets.QPushButton(self.buttonWidget)
|
|
||||||
self.convertButton.setMinimumSize(QtCore.QSize(0, 30))
|
|
||||||
font = QtGui.QFont()
|
|
||||||
font.setBold(True)
|
|
||||||
font.setWeight(75)
|
|
||||||
self.convertButton.setFont(font)
|
|
||||||
icon5 = QtGui.QIcon()
|
|
||||||
icon5.addPixmap(QtGui.QPixmap(":/Other/icons/convert.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
|
||||||
self.convertButton.setIcon(icon5)
|
|
||||||
self.convertButton.setObjectName("convertButton")
|
|
||||||
self.gridLayout_4.addWidget(self.convertButton, 1, 2, 1, 1)
|
|
||||||
self.clearButton = QtWidgets.QPushButton(self.buttonWidget)
|
|
||||||
self.clearButton.setMinimumSize(QtCore.QSize(0, 30))
|
|
||||||
icon6 = QtGui.QIcon()
|
|
||||||
icon6.addPixmap(QtGui.QPixmap(":/Other/icons/clear.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
|
||||||
self.clearButton.setIcon(icon6)
|
|
||||||
self.clearButton.setObjectName("clearButton")
|
|
||||||
self.gridLayout_4.addWidget(self.clearButton, 0, 2, 1, 1)
|
|
||||||
self.directoryButton.raise_()
|
|
||||||
self.clearButton.raise_()
|
|
||||||
self.fileButton.raise_()
|
|
||||||
self.deviceBox.raise_()
|
|
||||||
self.convertButton.raise_()
|
|
||||||
self.formatBox.raise_()
|
|
||||||
self.gridLayout.addWidget(self.buttonWidget, 3, 0, 1, 2)
|
|
||||||
mainWindow.setCentralWidget(self.centralWidget)
|
mainWindow.setCentralWidget(self.centralWidget)
|
||||||
self.statusBar = QtWidgets.QStatusBar(mainWindow)
|
self.statusBar = QtWidgets.QStatusBar(mainWindow)
|
||||||
self.statusBar.setSizeGripEnabled(False)
|
self.statusBar.setSizeGripEnabled(False)
|
||||||
@@ -222,52 +251,65 @@ class Ui_mainWindow(object):
|
|||||||
mainWindow.setTabOrder(self.gammaBox, self.borderBox)
|
mainWindow.setTabOrder(self.gammaBox, self.borderBox)
|
||||||
mainWindow.setTabOrder(self.borderBox, self.outputSplit)
|
mainWindow.setTabOrder(self.borderBox, self.outputSplit)
|
||||||
mainWindow.setTabOrder(self.outputSplit, self.colorBox)
|
mainWindow.setTabOrder(self.outputSplit, self.colorBox)
|
||||||
mainWindow.setTabOrder(self.colorBox, self.editorButton)
|
mainWindow.setTabOrder(self.colorBox, self.croppingBox)
|
||||||
|
mainWindow.setTabOrder(self.croppingBox, self.mozJpegBox)
|
||||||
|
mainWindow.setTabOrder(self.mozJpegBox, self.maximizeStrips)
|
||||||
|
mainWindow.setTabOrder(self.maximizeStrips, self.disableProcessingBox)
|
||||||
|
mainWindow.setTabOrder(self.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)
|
||||||
mainWindow.setTabOrder(self.jobList, self.gammaSlider)
|
mainWindow.setTabOrder(self.jobList, self.gammaSlider)
|
||||||
mainWindow.setTabOrder(self.gammaSlider, self.widthBox)
|
mainWindow.setTabOrder(self.gammaSlider, self.widthBox)
|
||||||
mainWindow.setTabOrder(self.widthBox, self.heightBox)
|
mainWindow.setTabOrder(self.widthBox, self.heightBox)
|
||||||
|
mainWindow.setTabOrder(self.heightBox, self.croppingPowerSlider)
|
||||||
|
|
||||||
def retranslateUi(self, mainWindow):
|
def retranslateUi(self, mainWindow):
|
||||||
_translate = QtCore.QCoreApplication.translate
|
_translate = QtCore.QCoreApplication.translate
|
||||||
mainWindow.setWindowTitle(_translate("mainWindow", "Kindle Comic Converter"))
|
mainWindow.setWindowTitle(_translate("mainWindow", "Kindle Comic Converter"))
|
||||||
self.hLabel.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Resolution of the target device.</p></body></html>"))
|
|
||||||
self.hLabel.setText(_translate("mainWindow", "Custom height:"))
|
|
||||||
self.widthBox.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Resolution of the target device.</p></body></html>"))
|
|
||||||
self.wLabel.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Resolution of the target device.</p></body></html>"))
|
|
||||||
self.wLabel.setText(_translate("mainWindow", "Custom width:"))
|
|
||||||
self.heightBox.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Resolution of the target device.</p></body></html>"))
|
|
||||||
self.mangaBox.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Enable right-to-left reading.</p></body></html>"))
|
|
||||||
self.mangaBox.setText(_translate("mainWindow", "Manga mode"))
|
|
||||||
self.rotateBox.setToolTip(_translate("mainWindow", "<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Split<br/></span>Double page spreads will be cut into two separate pages.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - Rotate and split<br/></span>Double page spreads will be displayed twice. First rotated and then split. </p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Rotate<br/></span>Double page spreads will be rotated.</p></body></html>"))
|
|
||||||
self.rotateBox.setText(_translate("mainWindow", "Spread splitter"))
|
|
||||||
self.qualityBox.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - 4 panels<br/></span>Zoom each corner separately.</p><p style=\'white-space:pre\'><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - 2 panels<br/></span>Zoom only the top and bottom of the page.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - 4 high-quality panels<br/></span>Zoom each corner separately. Try to increase the quality of magnification. Check wiki for more details.</p></body></html>"))
|
|
||||||
self.qualityBox.setText(_translate("mainWindow", "Panel View 4/2/HQ"))
|
|
||||||
self.webtoonBox.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Enable special parsing mode for Korean Webtoons.</p></body></html>"))
|
|
||||||
self.webtoonBox.setText(_translate("mainWindow", "Webtoon mode"))
|
|
||||||
self.upscaleBox.setToolTip(_translate("mainWindow", "<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Nothing<br/></span>Images smaller than device resolution will not be resized.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - Stretching<br/></span>Images smaller than device resolution will be resized. Aspect ratio will be not preserved.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Upscaling<br/></span>Images smaller than device resolution will be resized. Aspect ratio will be preserved.</p></body></html>"))
|
self.upscaleBox.setToolTip(_translate("mainWindow", "<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Nothing<br/></span>Images smaller than device resolution will not be resized.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - Stretching<br/></span>Images smaller than device resolution will be resized. Aspect ratio will be not preserved.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Upscaling<br/></span>Images smaller than device resolution will be resized. Aspect ratio will be preserved.</p></body></html>"))
|
||||||
self.upscaleBox.setText(_translate("mainWindow", "Stretch/Upscale"))
|
self.upscaleBox.setText(_translate("mainWindow", "Stretch/Upscale"))
|
||||||
|
self.rotateBox.setToolTip(_translate("mainWindow", "<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Split<br/></span>Double page spreads will be cut into two separate pages.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - Rotate and split<br/></span>Double page spreads will be displayed twice. First rotated and then split. </p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Rotate<br/></span>Double page spreads will be rotated.</p></body></html>"))
|
||||||
|
self.rotateBox.setText(_translate("mainWindow", "Spread splitter"))
|
||||||
|
self.outputSplit.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Automatic mode<br/></span>The output will be split automatically.</p><p style=\'white-space:pre\'><span style=\" font-weight:600; text-decoration: underline;\">Checked - Volume mode<br/></span>Every subdirectory will be considered as a separate volume.</p></body></html>"))
|
||||||
|
self.outputSplit.setText(_translate("mainWindow", "Output split"))
|
||||||
|
self.webtoonBox.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Enable special parsing mode for Korean Webtoons.</p></body></html>"))
|
||||||
|
self.webtoonBox.setText(_translate("mainWindow", "Webtoon mode"))
|
||||||
|
self.colorBox.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Disable conversion to grayscale.</p></body></html>"))
|
||||||
|
self.colorBox.setText(_translate("mainWindow", "Color mode"))
|
||||||
self.gammaBox.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Disable automatic gamma correction.</p></body></html>"))
|
self.gammaBox.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Disable automatic gamma correction.</p></body></html>"))
|
||||||
self.gammaBox.setText(_translate("mainWindow", "Custom gamma"))
|
self.gammaBox.setText(_translate("mainWindow", "Custom gamma"))
|
||||||
self.borderBox.setToolTip(_translate("mainWindow", "<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Autodetection<br/></span>The color of margins fill will be detected automatically.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - White<br/></span>Margins will be filled with white color.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Black<br/></span>Margins will be filled with black color.</p></body></html>"))
|
self.borderBox.setToolTip(_translate("mainWindow", "<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Autodetection<br/></span>The color of margins fill will be detected automatically.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - White<br/></span>Margins will be filled with white color.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Black<br/></span>Margins will be filled with black color.</p></body></html>"))
|
||||||
self.borderBox.setText(_translate("mainWindow", "W/B margins"))
|
self.borderBox.setText(_translate("mainWindow", "W/B margins"))
|
||||||
self.outputSplit.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Automatic mode<br/></span>The output will be split automatically.</p><p style=\'white-space:pre\'><span style=\" font-weight:600; text-decoration: underline;\">Checked - Volume mode<br/></span>Every subdirectory will be considered as a separate volume.</p></body></html>"))
|
self.mangaBox.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Enable right-to-left reading.</p></body></html>"))
|
||||||
self.outputSplit.setText(_translate("mainWindow", "Output split"))
|
self.mangaBox.setText(_translate("mainWindow", "Manga mode"))
|
||||||
self.colorBox.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Disable conversion to grayscale.</p></body></html>"))
|
self.qualityBox.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - 4 panels<br/></span>Zoom each corner separately.</p><p style=\'white-space:pre\'><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - 2 panels<br/></span>Zoom only the top and bottom of the page.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - 4 high-quality panels<br/></span>Zoom each corner separately. Try to increase the quality of magnification. Check wiki for more details.</p></body></html>"))
|
||||||
self.colorBox.setText(_translate("mainWindow", "Color mode"))
|
self.qualityBox.setText(_translate("mainWindow", "Panel View 4/2/HQ"))
|
||||||
|
self.mozJpegBox.setToolTip(_translate("mainWindow", "<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - JPEG<br/></span>Use JPEG files</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - force PNG<br/></span>Create PNG files instead JPEG</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - mozJpeg<br/></span>10-20% smaller JPEG file, with the same image quality, but processing time multiplied by 2</p></body></html>"))
|
||||||
|
self.mozJpegBox.setText(_translate("mainWindow", "JPEG/PNG/mozJpeg"))
|
||||||
|
self.maximizeStrips.setToolTip(_translate("mainWindow", "<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - 1x4<br/></span>Keep format 1x4 panels strips.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - 2x2<br/></span>Turn 1x4 strips to 2x2 to maximize screen usage.</p></body></html>"))
|
||||||
|
self.maximizeStrips.setText(_translate("mainWindow", "1x4 to 2x2 strips"))
|
||||||
|
self.croppingBox.setToolTip(_translate("mainWindow", "<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Disabled</span></p><p>Disabled</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - Margins<br/></span>Margins</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Margins + page numbers<br/></span>Margins +page numbers</p></body></html>"))
|
||||||
|
self.croppingBox.setText(_translate("mainWindow", "Cropping mode"))
|
||||||
|
self.disableProcessingBox.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Do not process any image, ignore profil and processing options</p></body></html>"))
|
||||||
|
self.disableProcessingBox.setText(_translate("mainWindow", "Disable processing"))
|
||||||
self.gammaLabel.setText(_translate("mainWindow", "Gamma: Auto"))
|
self.gammaLabel.setText(_translate("mainWindow", "Gamma: Auto"))
|
||||||
self.editorButton.setText(_translate("mainWindow", "Editor"))
|
self.croppingPowerLabel.setText(_translate("mainWindow", "Cropping power:"))
|
||||||
self.editorButton.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Shift+Click to edit directory.</p></body></html>"))
|
|
||||||
self.wikiButton.setText(_translate("mainWindow", "Wiki"))
|
|
||||||
self.directoryButton.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Add directory containing JPG, PNG or GIF files to queue.<br/><span style=\" font-weight:600;\">CBR, CBZ and CB7 files inside will not be processed!</span></p></body></html>"))
|
self.directoryButton.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Add directory containing JPG, PNG or GIF files to queue.<br/><span style=\" font-weight:600;\">CBR, CBZ and CB7 files inside will not be processed!</span></p></body></html>"))
|
||||||
self.directoryButton.setText(_translate("mainWindow", "Add directory"))
|
self.directoryButton.setText(_translate("mainWindow", "Add directory"))
|
||||||
self.fileButton.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Add CBR, CBZ, CB7 or PDF file to queue.</p></body></html>"))
|
self.fileButton.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Add CBR, CBZ, CB7 or PDF file to queue.</p></body></html>"))
|
||||||
self.fileButton.setText(_translate("mainWindow", "Add file"))
|
self.fileButton.setText(_translate("mainWindow", "Add file"))
|
||||||
self.deviceBox.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Target device.</p></body></html>"))
|
self.deviceBox.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Target device.</p></body></html>"))
|
||||||
self.formatBox.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Output format.</p></body></html>"))
|
self.formatBox.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Output format.</p></body></html>"))
|
||||||
self.convertButton.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Shift+Click to select the output directory.</p></body></html>"))
|
self.convertButton.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Shift+Click to select the output directory.</p></body></html>"))
|
||||||
self.convertButton.setText(_translate("mainWindow", "Convert"))
|
self.convertButton.setText(_translate("mainWindow", "Convert"))
|
||||||
self.clearButton.setText(_translate("mainWindow", "Clear list"))
|
self.clearButton.setText(_translate("mainWindow", "Clear list"))
|
||||||
|
self.editorButton.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Shift+Click to edit directory.</p></body></html>"))
|
||||||
|
self.editorButton.setText(_translate("mainWindow", "Editor"))
|
||||||
|
self.wikiButton.setText(_translate("mainWindow", "Wiki"))
|
||||||
|
self.hLabel.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Resolution of the target device.</p></body></html>"))
|
||||||
|
self.hLabel.setText(_translate("mainWindow", "Custom height:"))
|
||||||
|
self.widthBox.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Resolution of the target device.</p></body></html>"))
|
||||||
|
self.wLabel.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Resolution of the target device.</p></body></html>"))
|
||||||
|
self.wLabel.setText(_translate("mainWindow", "Custom width:"))
|
||||||
|
self.heightBox.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Resolution of the target device.</p></body></html>"))
|
||||||
from . import KCC_rc
|
from . import KCC_rc
|
||||||
|
|||||||
@@ -1,13 +1,16 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
# Form implementation generated from reading ui file 'gui\MetaEditor.ui'
|
# Form implementation generated from reading ui file 'gui/MetaEditor.ui'
|
||||||
#
|
#
|
||||||
# Created by: PyQt5 UI code generator 5.6
|
# Created by: PyQt5 UI code generator 5.15.2
|
||||||
#
|
#
|
||||||
# WARNING! All changes made in this file will be lost!
|
# 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.
|
||||||
|
|
||||||
|
|
||||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
class Ui_editorDialog(object):
|
class Ui_editorDialog(object):
|
||||||
def setupUi(self, editorDialog):
|
def setupUi(self, editorDialog):
|
||||||
editorDialog.setObjectName("editorDialog")
|
editorDialog.setObjectName("editorDialog")
|
||||||
@@ -66,13 +69,6 @@ class Ui_editorDialog(object):
|
|||||||
self.coloristLine = QtWidgets.QLineEdit(self.editorWidget)
|
self.coloristLine = QtWidgets.QLineEdit(self.editorWidget)
|
||||||
self.coloristLine.setObjectName("coloristLine")
|
self.coloristLine.setObjectName("coloristLine")
|
||||||
self.gridLayout.addWidget(self.coloristLine, 6, 1, 1, 1)
|
self.gridLayout.addWidget(self.coloristLine, 6, 1, 1, 1)
|
||||||
self.label_8 = QtWidgets.QLabel(self.editorWidget)
|
|
||||||
self.label_8.setOpenExternalLinks(True)
|
|
||||||
self.label_8.setObjectName("label_8")
|
|
||||||
self.gridLayout.addWidget(self.label_8, 7, 0, 1, 1)
|
|
||||||
self.muidLine = QtWidgets.QLineEdit(self.editorWidget)
|
|
||||||
self.muidLine.setObjectName("muidLine")
|
|
||||||
self.gridLayout.addWidget(self.muidLine, 7, 1, 1, 1)
|
|
||||||
self.verticalLayout.addWidget(self.editorWidget)
|
self.verticalLayout.addWidget(self.editorWidget)
|
||||||
self.optionWidget = QtWidgets.QWidget(editorDialog)
|
self.optionWidget = QtWidgets.QWidget(editorDialog)
|
||||||
self.optionWidget.setObjectName("optionWidget")
|
self.optionWidget.setObjectName("optionWidget")
|
||||||
@@ -117,8 +113,6 @@ class Ui_editorDialog(object):
|
|||||||
self.label_5.setText(_translate("editorDialog", "Penciller:"))
|
self.label_5.setText(_translate("editorDialog", "Penciller:"))
|
||||||
self.label_6.setText(_translate("editorDialog", "Inker:"))
|
self.label_6.setText(_translate("editorDialog", "Inker:"))
|
||||||
self.label_7.setText(_translate("editorDialog", "Colorist:"))
|
self.label_7.setText(_translate("editorDialog", "Colorist:"))
|
||||||
self.label_8.setText(_translate("editorDialog", "<html><head/><body><p><a href=\"https://github.com/ciromattia/kcc/wiki/Manga-Cover-Database-support\"><span style=\" text-decoration: underline; color:#0000ff;\">MUid:</span></a></p></body></html>"))
|
|
||||||
self.okButton.setText(_translate("editorDialog", "Save"))
|
self.okButton.setText(_translate("editorDialog", "Save"))
|
||||||
self.cancelButton.setText(_translate("editorDialog", "Cancel"))
|
self.cancelButton.setText(_translate("editorDialog", "Cancel"))
|
||||||
|
|
||||||
from . import KCC_rc
|
from . import KCC_rc
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
__version__ = '5.4.5'
|
__version__ = '5.6.1'
|
||||||
__license__ = 'ISC'
|
__license__ = 'ISC'
|
||||||
__copyright__ = '2012-2018, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>'
|
__copyright__ = '2012-2022, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>, darodi'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|||||||
@@ -1,89 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
#
|
|
||||||
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
|
||||||
# Copyright (c) 2013-2018 Pawel Jastrzebski <pawelj@iosphe.re>
|
|
||||||
#
|
|
||||||
# Permission to use, copy, modify, and/or distribute this software for
|
|
||||||
# any purpose with or without fee is hereby granted, provided that the
|
|
||||||
# above copyright notice and this permission notice appear in all
|
|
||||||
# copies.
|
|
||||||
#
|
|
||||||
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
|
||||||
# WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
|
||||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
|
||||||
# AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
|
||||||
# DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
|
|
||||||
# OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
|
||||||
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
||||||
# PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
#
|
|
||||||
|
|
||||||
import os
|
|
||||||
from zipfile import is_zipfile, ZipFile
|
|
||||||
from subprocess import STDOUT, PIPE
|
|
||||||
from psutil import Popen
|
|
||||||
from shutil import move
|
|
||||||
from . import rarfile
|
|
||||||
from .shared import check7ZFile as is_7zfile
|
|
||||||
|
|
||||||
|
|
||||||
class CBxArchive:
|
|
||||||
def __init__(self, fname):
|
|
||||||
self.fname = fname
|
|
||||||
if is_zipfile(fname):
|
|
||||||
self.compressor = 'zip'
|
|
||||||
elif rarfile.is_rarfile(fname):
|
|
||||||
self.compressor = 'rar'
|
|
||||||
elif is_7zfile(fname):
|
|
||||||
self.compressor = '7z'
|
|
||||||
else:
|
|
||||||
self.compressor = None
|
|
||||||
|
|
||||||
def isCbxFile(self):
|
|
||||||
return self.compressor is not None
|
|
||||||
|
|
||||||
def extractCBZ(self, targetdir):
|
|
||||||
cbzFile = ZipFile(self.fname)
|
|
||||||
filelist = []
|
|
||||||
for f in cbzFile.namelist():
|
|
||||||
if f.startswith('__MACOSX') or f.endswith('.DS_Store') or f.endswith('humbs.db'):
|
|
||||||
pass
|
|
||||||
elif f.endswith('/'):
|
|
||||||
os.makedirs(os.path.join(targetdir, f), exist_ok=True)
|
|
||||||
else:
|
|
||||||
filelist.append(f)
|
|
||||||
cbzFile.extractall(targetdir, filelist)
|
|
||||||
|
|
||||||
def extractCBR(self, targetdir):
|
|
||||||
cbrFile = rarfile.RarFile(self.fname)
|
|
||||||
cbrFile.extractall(targetdir)
|
|
||||||
for root, _, filenames in os.walk(targetdir):
|
|
||||||
for filename in filenames:
|
|
||||||
if filename.startswith('__MACOSX') or filename.endswith('.DS_Store') or filename.endswith('humbs.db'):
|
|
||||||
os.remove(os.path.join(root, filename))
|
|
||||||
|
|
||||||
def extractCB7(self, targetdir):
|
|
||||||
output = Popen('7za x "' + self.fname + '" -xr!__MACOSX -xr!.DS_Store -xr!thumbs.db -xr!Thumbs.db -o"' +
|
|
||||||
targetdir + '"', stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=True)
|
|
||||||
extracted = False
|
|
||||||
for line in output.stdout:
|
|
||||||
if b"Everything is Ok" in line:
|
|
||||||
extracted = True
|
|
||||||
if not extracted:
|
|
||||||
raise OSError
|
|
||||||
|
|
||||||
def extract(self, targetdir):
|
|
||||||
if self.compressor == 'rar':
|
|
||||||
self.extractCBR(targetdir)
|
|
||||||
elif self.compressor == 'zip':
|
|
||||||
self.extractCBZ(targetdir)
|
|
||||||
elif self.compressor == '7z':
|
|
||||||
self.extractCB7(targetdir)
|
|
||||||
adir = os.listdir(targetdir)
|
|
||||||
if 'ComicInfo.xml' in adir:
|
|
||||||
adir.remove('ComicInfo.xml')
|
|
||||||
if len(adir) == 1 and os.path.isdir(os.path.join(targetdir, adir[0])):
|
|
||||||
for f in os.listdir(os.path.join(targetdir, adir[0])):
|
|
||||||
move(os.path.join(targetdir, adir[0], f), targetdir)
|
|
||||||
os.rmdir(os.path.join(targetdir, adir[0]))
|
|
||||||
return targetdir
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
||||||
# Copyright (c) 2013-2018 Pawel Jastrzebski <pawelj@iosphe.re>
|
# Copyright (c) 2013-2019 Pawel Jastrzebski <pawelj@iosphe.re>
|
||||||
#
|
#
|
||||||
# Permission to use, copy, modify, and/or distribute this software for
|
# Permission to use, copy, modify, and/or distribute this software for
|
||||||
# any purpose with or without fee is hereby granted, provided that the
|
# any purpose with or without fee is hereby granted, provided that the
|
||||||
@@ -22,14 +22,12 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
from time import strftime, gmtime
|
from time import strftime, gmtime
|
||||||
from copy import copy
|
from copy import copy
|
||||||
from glob import glob
|
from glob import glob, escape
|
||||||
from json import loads
|
|
||||||
from urllib.request import Request, urlopen
|
|
||||||
from re import sub
|
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 optparse import OptionParser, OptionGroup
|
||||||
from multiprocessing import Pool
|
from multiprocessing import Pool
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
@@ -37,7 +35,7 @@ from slugify import slugify as slugifyExt
|
|||||||
from PIL import Image
|
from PIL import Image
|
||||||
from subprocess import STDOUT, PIPE
|
from subprocess import STDOUT, PIPE
|
||||||
from psutil import Popen, virtual_memory, disk_usage
|
from psutil import Popen, virtual_memory, disk_usage
|
||||||
from html import escape
|
from html import escape as hescape
|
||||||
try:
|
try:
|
||||||
from PyQt5 import QtCore
|
from PyQt5 import QtCore
|
||||||
except ImportError:
|
except ImportError:
|
||||||
@@ -45,7 +43,7 @@ except ImportError:
|
|||||||
from .shared import md5Checksum, getImageFileName, walkSort, walkLevel, sanitizeTrace
|
from .shared import md5Checksum, getImageFileName, walkSort, walkLevel, sanitizeTrace
|
||||||
from . import comic2panel
|
from . import comic2panel
|
||||||
from . import image
|
from . import image
|
||||||
from . import cbxarchive
|
from . import comicarchive
|
||||||
from . import pdfjpgextract
|
from . import pdfjpgextract
|
||||||
from . import dualmetafix
|
from . import dualmetafix
|
||||||
from . import metadata
|
from . import metadata
|
||||||
@@ -61,7 +59,7 @@ def main(argv=None):
|
|||||||
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(arg)])
|
sources = set([source for arg in args for source in glob(escape(arg))])
|
||||||
else:
|
else:
|
||||||
sources = set(args)
|
sources = set(args)
|
||||||
if len(sources) == 0:
|
if len(sources) == 0:
|
||||||
@@ -70,7 +68,7 @@ def main(argv=None):
|
|||||||
for source in sources:
|
for source in sources:
|
||||||
source = source.rstrip('\\').rstrip('/')
|
source = source.rstrip('\\').rstrip('/')
|
||||||
options = copy(optionstemplate)
|
options = copy(optionstemplate)
|
||||||
checkOptions()
|
options = checkOptions(options)
|
||||||
if len(sources) > 1:
|
if len(sources) > 1:
|
||||||
print('Working on ' + source + '...')
|
print('Working on ' + source + '...')
|
||||||
makeBook(source)
|
makeBook(source)
|
||||||
@@ -81,11 +79,11 @@ def buildHTML(path, imgfile, imgfilepath):
|
|||||||
imgfilepath = md5Checksum(imgfilepath)
|
imgfilepath = md5Checksum(imgfilepath)
|
||||||
filename = getImageFileName(imgfile)
|
filename = getImageFileName(imgfile)
|
||||||
deviceres = options.profileData[1]
|
deviceres = options.profileData[1]
|
||||||
if "Rotated" in options.imgMetadata[imgfilepath]:
|
if not options.noprocessing and "Rotated" in options.imgMetadata[imgfilepath]:
|
||||||
rotatedPage = True
|
rotatedPage = True
|
||||||
else:
|
else:
|
||||||
rotatedPage = False
|
rotatedPage = False
|
||||||
if "BlackBackground" in options.imgMetadata[imgfilepath]:
|
if not options.noprocessing and "BlackBackground" in options.imgMetadata[imgfilepath]:
|
||||||
additionalStyle = 'background-color:#000000;'
|
additionalStyle = 'background-color:#000000;'
|
||||||
else:
|
else:
|
||||||
additionalStyle = ''
|
additionalStyle = ''
|
||||||
@@ -112,7 +110,7 @@ def buildHTML(path, imgfile, imgfilepath):
|
|||||||
"<!DOCTYPE html>\n",
|
"<!DOCTYPE html>\n",
|
||||||
"<html xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:epub=\"http://www.idpf.org/2007/ops\">\n",
|
"<html xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:epub=\"http://www.idpf.org/2007/ops\">\n",
|
||||||
"<head>\n",
|
"<head>\n",
|
||||||
"<title>", escape(filename[0]), "</title>\n",
|
"<title>", hescape(filename[0]), "</title>\n",
|
||||||
"<link href=\"", "../" * (backref - 1), "style.css\" type=\"text/css\" rel=\"stylesheet\"/>\n",
|
"<link href=\"", "../" * (backref - 1), "style.css\" type=\"text/css\" rel=\"stylesheet\"/>\n",
|
||||||
"<meta name=\"viewport\" "
|
"<meta name=\"viewport\" "
|
||||||
"content=\"width=" + str(imgsize[0]) + ", height=" + str(imgsize[1]) + "\"/>\n"
|
"content=\"width=" + str(imgsize[0]) + ", height=" + str(imgsize[1]) + "\"/>\n"
|
||||||
@@ -210,7 +208,7 @@ def buildNCX(dstdir, title, chapters, chapternames):
|
|||||||
"<meta name=\"dtb:maxPageNumber\" content=\"0\"/>\n",
|
"<meta name=\"dtb:maxPageNumber\" content=\"0\"/>\n",
|
||||||
"<meta name=\"generated\" content=\"true\"/>\n",
|
"<meta name=\"generated\" content=\"true\"/>\n",
|
||||||
"</head>\n",
|
"</head>\n",
|
||||||
"<docTitle><text>", escape(title), "</text></docTitle>\n",
|
"<docTitle><text>", hescape(title), "</text></docTitle>\n",
|
||||||
"<navMap>\n"])
|
"<navMap>\n"])
|
||||||
for chapter in chapters:
|
for chapter in chapters:
|
||||||
folder = chapter[0].replace(os.path.join(dstdir, 'OEBPS'), '').lstrip('/').lstrip('\\\\')
|
folder = chapter[0].replace(os.path.join(dstdir, 'OEBPS'), '').lstrip('/').lstrip('\\\\')
|
||||||
@@ -222,7 +220,7 @@ def buildNCX(dstdir, title, chapters, chapternames):
|
|||||||
elif os.path.basename(folder) != "Text":
|
elif os.path.basename(folder) != "Text":
|
||||||
title = chapternames[os.path.basename(folder)]
|
title = chapternames[os.path.basename(folder)]
|
||||||
f.write("<navPoint id=\"" + navID + "\"><navLabel><text>" +
|
f.write("<navPoint id=\"" + navID + "\"><navLabel><text>" +
|
||||||
escape(title) + "</text></navLabel><content src=\"" + filename[0].replace("\\", "/") +
|
hescape(title) + "</text></navLabel><content src=\"" + filename[0].replace("\\", "/") +
|
||||||
".xhtml\"/></navPoint>\n")
|
".xhtml\"/></navPoint>\n")
|
||||||
f.write("</navMap>\n</ncx>")
|
f.write("</navMap>\n</ncx>")
|
||||||
f.close()
|
f.close()
|
||||||
@@ -235,7 +233,7 @@ def buildNAV(dstdir, title, chapters, chapternames):
|
|||||||
"<!DOCTYPE html>\n",
|
"<!DOCTYPE html>\n",
|
||||||
"<html xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:epub=\"http://www.idpf.org/2007/ops\">\n",
|
"<html xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:epub=\"http://www.idpf.org/2007/ops\">\n",
|
||||||
"<head>\n",
|
"<head>\n",
|
||||||
"<title>" + escape(title) + "</title>\n",
|
"<title>" + hescape(title) + "</title>\n",
|
||||||
"<meta charset=\"utf-8\"/>\n",
|
"<meta charset=\"utf-8\"/>\n",
|
||||||
"</head>\n",
|
"</head>\n",
|
||||||
"<body>\n",
|
"<body>\n",
|
||||||
@@ -248,7 +246,7 @@ def buildNAV(dstdir, title, chapters, chapternames):
|
|||||||
title = chapternames[chapter[1]]
|
title = chapternames[chapter[1]]
|
||||||
elif os.path.basename(folder) != "Text":
|
elif os.path.basename(folder) != "Text":
|
||||||
title = chapternames[os.path.basename(folder)]
|
title = chapternames[os.path.basename(folder)]
|
||||||
f.write("<li><a href=\"" + filename[0].replace("\\", "/") + ".xhtml\">" + escape(title) + "</a></li>\n")
|
f.write("<li><a href=\"" + filename[0].replace("\\", "/") + ".xhtml\">" + hescape(title) + "</a></li>\n")
|
||||||
f.writelines(["</ol>\n",
|
f.writelines(["</ol>\n",
|
||||||
"</nav>\n",
|
"</nav>\n",
|
||||||
"<nav epub:type=\"page-list\">\n",
|
"<nav epub:type=\"page-list\">\n",
|
||||||
@@ -260,7 +258,7 @@ def buildNAV(dstdir, title, chapters, chapternames):
|
|||||||
title = chapternames[chapter[1]]
|
title = chapternames[chapter[1]]
|
||||||
elif os.path.basename(folder) != "Text":
|
elif os.path.basename(folder) != "Text":
|
||||||
title = chapternames[os.path.basename(folder)]
|
title = chapternames[os.path.basename(folder)]
|
||||||
f.write("<li><a href=\"" + filename[0].replace("\\", "/") + ".xhtml\">" + escape(title) + "</a></li>\n")
|
f.write("<li><a href=\"" + filename[0].replace("\\", "/") + ".xhtml\">" + hescape(title) + "</a></li>\n")
|
||||||
f.write("</ol>\n</nav>\n</body>\n</html>")
|
f.write("</ol>\n</nav>\n</body>\n</html>")
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
@@ -278,7 +276,7 @@ def buildOPF(dstdir, title, filelist, cover=None):
|
|||||||
"xmlns=\"http://www.idpf.org/2007/opf\">\n",
|
"xmlns=\"http://www.idpf.org/2007/opf\">\n",
|
||||||
"<metadata xmlns:opf=\"http://www.idpf.org/2007/opf\" ",
|
"<metadata xmlns:opf=\"http://www.idpf.org/2007/opf\" ",
|
||||||
"xmlns:dc=\"http://purl.org/dc/elements/1.1/\">\n",
|
"xmlns:dc=\"http://purl.org/dc/elements/1.1/\">\n",
|
||||||
"<dc:title>", title, "</dc:title>\n",
|
"<dc:title>", hescape(title), "</dc:title>\n",
|
||||||
"<dc:language>en-US</dc:language>\n",
|
"<dc:language>en-US</dc:language>\n",
|
||||||
"<dc:identifier id=\"BookID\">urn:uuid:", options.uuid, "</dc:identifier>\n",
|
"<dc:identifier id=\"BookID\">urn:uuid:", options.uuid, "</dc:identifier>\n",
|
||||||
"<dc:contributor id=\"contributor\">KindleComicConverter-" + __version__ + "</dc:contributor>\n"])
|
"<dc:contributor id=\"contributor\">KindleComicConverter-" + __version__ + "</dc:contributor>\n"])
|
||||||
@@ -304,6 +302,11 @@ def buildOPF(dstdir, title, filelist, cover=None):
|
|||||||
else:
|
else:
|
||||||
f.writelines(["<meta name=\"orientation-lock\" content=\"portrait\"/>\n",
|
f.writelines(["<meta name=\"orientation-lock\" content=\"portrait\"/>\n",
|
||||||
"<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",
|
||||||
@@ -336,38 +339,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:
|
||||||
@@ -559,9 +588,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:
|
||||||
@@ -597,16 +626,12 @@ def getWorkFolder(afile):
|
|||||||
raise UserWarning("Failed to extract images from PDF file.")
|
raise UserWarning("Failed to extract images from PDF file.")
|
||||||
else:
|
else:
|
||||||
workdir = mkdtemp('', 'KCC-')
|
workdir = mkdtemp('', 'KCC-')
|
||||||
cbx = cbxarchive.CBxArchive(afile)
|
try:
|
||||||
if cbx.isCbxFile():
|
cbx = comicarchive.ComicArchive(afile)
|
||||||
try:
|
path = cbx.extract(workdir)
|
||||||
path = cbx.extract(workdir)
|
except OSError as e:
|
||||||
except Exception:
|
|
||||||
rmtree(workdir, True)
|
|
||||||
raise UserWarning("Failed to extract archive.")
|
|
||||||
else:
|
|
||||||
rmtree(workdir, True)
|
rmtree(workdir, True)
|
||||||
raise UserWarning("Failed to detect archive format.")
|
raise UserWarning(e.strerror)
|
||||||
else:
|
else:
|
||||||
raise UserWarning("Failed to open source file/directory.")
|
raise UserWarning("Failed to open source file/directory.")
|
||||||
sanitizePermissions(path)
|
sanitizePermissions(path)
|
||||||
@@ -652,7 +677,6 @@ def getOutputFilename(srcpath, wantedname, ext, tomenumber):
|
|||||||
def getComicInfo(path, originalpath):
|
def getComicInfo(path, originalpath):
|
||||||
xmlPath = os.path.join(path, 'ComicInfo.xml')
|
xmlPath = os.path.join(path, 'ComicInfo.xml')
|
||||||
options.authors = ['KCC']
|
options.authors = ['KCC']
|
||||||
options.remoteCovers = {}
|
|
||||||
options.chapters = []
|
options.chapters = []
|
||||||
options.summary = ''
|
options.summary = ''
|
||||||
titleSuffix = ''
|
titleSuffix = ''
|
||||||
@@ -673,7 +697,7 @@ def getComicInfo(path, originalpath):
|
|||||||
options.authors = []
|
options.authors = []
|
||||||
if defaultTitle:
|
if defaultTitle:
|
||||||
if xml.data['Series']:
|
if xml.data['Series']:
|
||||||
options.title = escape(xml.data['Series'])
|
options.title = hescape(xml.data['Series'])
|
||||||
if xml.data['Volume']:
|
if xml.data['Volume']:
|
||||||
titleSuffix += ' V' + xml.data['Volume'].zfill(2)
|
titleSuffix += ' V' + xml.data['Volume'].zfill(2)
|
||||||
if xml.data['Number']:
|
if xml.data['Number']:
|
||||||
@@ -681,35 +705,19 @@ def getComicInfo(path, originalpath):
|
|||||||
options.title += titleSuffix
|
options.title += titleSuffix
|
||||||
for field in ['Writers', 'Pencillers', 'Inkers', 'Colorists']:
|
for field in ['Writers', 'Pencillers', 'Inkers', 'Colorists']:
|
||||||
for person in xml.data[field]:
|
for person in xml.data[field]:
|
||||||
options.authors.append(escape(person))
|
options.authors.append(hescape(person))
|
||||||
if len(options.authors) > 0:
|
if len(options.authors) > 0:
|
||||||
options.authors = list(set(options.authors))
|
options.authors = list(set(options.authors))
|
||||||
options.authors.sort()
|
options.authors.sort()
|
||||||
else:
|
else:
|
||||||
options.authors = ['KCC']
|
options.authors = ['KCC']
|
||||||
if xml.data['MUid']:
|
|
||||||
options.remoteCovers = getCoversFromMCB(xml.data['MUid'])
|
|
||||||
if xml.data['Bookmarks']:
|
if xml.data['Bookmarks']:
|
||||||
options.chapters = xml.data['Bookmarks']
|
options.chapters = xml.data['Bookmarks']
|
||||||
if xml.data['Summary']:
|
if xml.data['Summary']:
|
||||||
options.summary = escape(xml.data['Summary'])
|
options.summary = hescape(xml.data['Summary'])
|
||||||
os.remove(xmlPath)
|
os.remove(xmlPath)
|
||||||
|
|
||||||
|
|
||||||
def getCoversFromMCB(mangaid):
|
|
||||||
covers = {}
|
|
||||||
try:
|
|
||||||
jsonRaw = urlopen(Request('http://mcd.iosphe.re/api/v1/series/' + mangaid + '/',
|
|
||||||
headers={'User-Agent': 'KindleComicConverter/' + __version__}))
|
|
||||||
jsonData = loads(jsonRaw.read().decode('utf-8'))
|
|
||||||
for volume in jsonData['Covers']['a']:
|
|
||||||
if volume['Side'] == 'front':
|
|
||||||
covers[int(volume['Volume'])] = volume['Raw']
|
|
||||||
except Exception:
|
|
||||||
return {}
|
|
||||||
return covers
|
|
||||||
|
|
||||||
|
|
||||||
def getDirectorySize(start_path='.'):
|
def getDirectorySize(start_path='.'):
|
||||||
total_size = 0
|
total_size = 0
|
||||||
for dirpath, _, filenames in os.walk(start_path):
|
for dirpath, _, filenames in os.walk(start_path):
|
||||||
@@ -790,7 +798,8 @@ def splitDirectory(path):
|
|||||||
level = -1
|
level = -1
|
||||||
for root, _, files in os.walk(os.path.join(path, 'OEBPS', 'Images')):
|
for root, _, files in os.walk(os.path.join(path, 'OEBPS', 'Images')):
|
||||||
for f in files:
|
for f in files:
|
||||||
if f.endswith('.jpg') or f.endswith('.jpeg') or f.endswith('.png') or f.endswith('.gif'):
|
if f.endswith('.jpg') or f.endswith('.jpeg') or f.endswith('.png') or f.endswith('.gif') or \
|
||||||
|
f.endswith('.webp'):
|
||||||
newLevel = os.path.join(root, f).replace(os.path.join(path, 'OEBPS', 'Images'), '').count(os.sep)
|
newLevel = os.path.join(root, f).replace(os.path.join(path, 'OEBPS', 'Images'), '').count(os.sep)
|
||||||
if level != -1 and level != newLevel:
|
if level != -1 and level != newLevel:
|
||||||
level = 0
|
level = 0
|
||||||
@@ -811,7 +820,9 @@ def splitProcess(path, mode):
|
|||||||
output = []
|
output = []
|
||||||
currentSize = 0
|
currentSize = 0
|
||||||
currentTarget = path
|
currentTarget = path
|
||||||
if options.webtoon:
|
if options.targetsize:
|
||||||
|
targetSize = options.targetsize * 1048576
|
||||||
|
elif options.webtoon:
|
||||||
targetSize = 104857600
|
targetSize = 104857600
|
||||||
else:
|
else:
|
||||||
targetSize = 419430400
|
targetSize = 419430400
|
||||||
@@ -872,7 +883,7 @@ def detectCorruption(tmppath, orgpath):
|
|||||||
if 'decoder' in str(err) and 'not available' in str(err):
|
if 'decoder' in str(err) and 'not available' in str(err):
|
||||||
raise RuntimeError('Pillow was compiled without JPG and/or PNG decoder.')
|
raise RuntimeError('Pillow was compiled without JPG and/or PNG decoder.')
|
||||||
else:
|
else:
|
||||||
raise RuntimeError('Image file %s is corrupted.' % pathOrg)
|
raise RuntimeError('Image file %s is corrupted. Error: %s' % (pathOrg, str(err)))
|
||||||
else:
|
else:
|
||||||
os.remove(os.path.join(root, name))
|
os.remove(os.path.join(root, name))
|
||||||
if alreadyProcessed:
|
if alreadyProcessed:
|
||||||
@@ -931,8 +942,9 @@ def makeParser():
|
|||||||
otherOptions = OptionGroup(psr, "OTHER")
|
otherOptions = OptionGroup(psr, "OTHER")
|
||||||
|
|
||||||
mainOptions.add_option("-p", "--profile", action="store", dest="profile", default="KV",
|
mainOptions.add_option("-p", "--profile", action="store", dest="profile", default="KV",
|
||||||
help="Device profile (Available options: K1, K2, K34, K578, KDX, KPW, KV, KO, KoMT, KoG,"
|
help="Device profile (Available options: K1, K2, K34, K578, KDX, KPW, KPW5, KV, KO, "
|
||||||
" KoGHD, KoA, KoAHD, KoAH2O, KoAO) [Default=KV]")
|
"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,
|
mainOptions.add_option("-m", "--manga-style", action="store_true", dest="righttoleft", default=False,
|
||||||
help="Manga style (right-to-left reading and splitting)")
|
help="Manga style (right-to-left reading and splitting)")
|
||||||
mainOptions.add_option("-q", "--hq", action="store_true", dest="hq", default=False,
|
mainOptions.add_option("-q", "--hq", action="store_true", dest="hq", default=False,
|
||||||
@@ -941,17 +953,23 @@ def makeParser():
|
|||||||
help="Display two not four panels in Panel View mode")
|
help="Display two not four panels in Panel View mode")
|
||||||
mainOptions.add_option("-w", "--webtoon", action="store_true", dest="webtoon", default=False,
|
mainOptions.add_option("-w", "--webtoon", action="store_true", dest="webtoon", default=False,
|
||||||
help="Webtoon processing mode"),
|
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,
|
outputOptions.add_option("-o", "--output", action="store", dest="output", default=None,
|
||||||
help="Output generated file to specified directory or file")
|
help="Output generated file to specified directory or file")
|
||||||
outputOptions.add_option("-t", "--title", action="store", dest="title", default="defaulttitle",
|
outputOptions.add_option("-t", "--title", action="store", dest="title", default="defaulttitle",
|
||||||
help="Comic title [Default=filename or directory name]")
|
help="Comic title [Default=filename or directory name]")
|
||||||
outputOptions.add_option("-f", "--format", action="store", dest="format", default="Auto",
|
outputOptions.add_option("-f", "--format", action="store", dest="format", default="Auto",
|
||||||
help="Output format (Available options: Auto, MOBI, EPUB, CBZ, KFX) [Default=Auto]")
|
help="Output format (Available options: Auto, MOBI, EPUB, CBZ, KFX, MOBI+EPUB) "
|
||||||
|
"[Default=Auto]")
|
||||||
outputOptions.add_option("-b", "--batchsplit", type="int", dest="batchsplit", default="0",
|
outputOptions.add_option("-b", "--batchsplit", type="int", dest="batchsplit", default="0",
|
||||||
help="Split output into multiple files. 0: Don't split 1: Automatic mode "
|
help="Split output into multiple files. 0: Don't split 1: Automatic mode "
|
||||||
"2: Consider every subdirectory as separate volume [Default=0]")
|
"2: Consider every subdirectory as separate volume [Default=0]")
|
||||||
|
|
||||||
|
processingOptions.add_option("-n", "--noprocessing", action="store_true", dest="noprocessing", default=False,
|
||||||
|
help="Do not modify image and ignore any profil or processing option")
|
||||||
processingOptions.add_option("-u", "--upscale", action="store_true", dest="upscale", default=False,
|
processingOptions.add_option("-u", "--upscale", action="store_true", dest="upscale", default=False,
|
||||||
help="Resize images smaller than device's resolution")
|
help="Resize images smaller than device's resolution")
|
||||||
processingOptions.add_option("-s", "--stretch", action="store_true", dest="stretch", default=False,
|
processingOptions.add_option("-s", "--stretch", action="store_true", dest="stretch", default=False,
|
||||||
@@ -964,6 +982,8 @@ def makeParser():
|
|||||||
help="Set cropping mode. 0: Disabled 1: Margins 2: Margins + page numbers [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",
|
processingOptions.add_option("--cp", "--croppingpower", type="float", dest="croppingp", default="1.0",
|
||||||
help="Set cropping power [Default=1.0]")
|
help="Set cropping power [Default=1.0]")
|
||||||
|
processingOptions.add_option("--cm", "--croppingminimum", type="float", dest="croppingm", default="0.0",
|
||||||
|
help="Set cropping minimum area ratio [Default=0.0]")
|
||||||
processingOptions.add_option("--blackborders", action="store_true", dest="black_borders", default=False,
|
processingOptions.add_option("--blackborders", action="store_true", dest="black_borders", default=False,
|
||||||
help="Disable autodetection and force black borders")
|
help="Disable autodetection and force black borders")
|
||||||
processingOptions.add_option("--whiteborders", action="store_true", dest="white_borders", default=False,
|
processingOptions.add_option("--whiteborders", action="store_true", dest="white_borders", default=False,
|
||||||
@@ -972,7 +992,10 @@ def makeParser():
|
|||||||
help="Don't convert images to grayscale")
|
help="Don't convert images to grayscale")
|
||||||
processingOptions.add_option("--forcepng", action="store_true", dest="forcepng", default=False,
|
processingOptions.add_option("--forcepng", action="store_true", dest="forcepng", default=False,
|
||||||
help="Create PNG files instead JPEG")
|
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,
|
customProfileOptions.add_option("--customwidth", type="int", dest="customwidth", default=0,
|
||||||
help="Replace screen width provided by device profile")
|
help="Replace screen width provided by device profile")
|
||||||
customProfileOptions.add_option("--customheight", type="int", dest="customheight", default=0,
|
customProfileOptions.add_option("--customheight", type="int", dest="customheight", default=0,
|
||||||
@@ -989,21 +1012,38 @@ def makeParser():
|
|||||||
return psr
|
return psr
|
||||||
|
|
||||||
|
|
||||||
def checkOptions():
|
def checkOptions(options):
|
||||||
global 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
|
||||||
|
if options.format == 'EPUB-200MB':
|
||||||
|
options.targetsize = 200
|
||||||
|
options.format = 'EPUB'
|
||||||
|
if options.batchsplit != 2:
|
||||||
|
options.batchsplit = 1
|
||||||
|
if options.format == 'MOBI+EPUB':
|
||||||
|
options.keep_epub = True
|
||||||
|
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', 'KV', 'KO']:
|
if options.profile in ['K1', 'K2', 'K34', 'K578', 'KPW', 'KPW5', 'KV', 'KO', 'K11', 'KS']:
|
||||||
options.format = 'MOBI'
|
options.format = 'MOBI'
|
||||||
elif options.profile in ['OTHER', 'KoMT', 'KoG', 'KoGHD', 'KoA', 'KoAHD', 'KoAH2O', 'KoAO']:
|
elif options.profile in ['OTHER', 'KoMT', 'KoG', 'KoGHD', 'KoA', 'KoAHD', 'KoAH2O', 'KoAO',
|
||||||
|
'KoN', 'KoC', 'KoL', 'KoF', 'KoS', 'KoE']:
|
||||||
options.format = 'EPUB'
|
options.format = 'EPUB'
|
||||||
elif options.profile in ['KDX']:
|
elif options.profile in ['KDX']:
|
||||||
options.format = 'CBZ'
|
options.format = 'CBZ'
|
||||||
if options.profile in ['K1', 'K2', 'K34', 'K578', 'KPW', 'KV', 'KO']:
|
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:
|
||||||
@@ -1049,25 +1089,22 @@ def checkOptions():
|
|||||||
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]
|
||||||
|
return options
|
||||||
|
|
||||||
|
|
||||||
def checkTools(source):
|
def checkTools(source):
|
||||||
source = source.upper()
|
source = source.upper()
|
||||||
if source.endswith('.CBR') or source.endswith('.RAR'):
|
if source.endswith('.CB7') or source.endswith('.7Z') or source.endswith('.RAR') or source.endswith('.CBR') or \
|
||||||
rarExitCode = Popen('unrar', stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=True)
|
source.endswith('.ZIP') or source.endswith('.CBZ'):
|
||||||
rarExitCode = rarExitCode.wait()
|
process = Popen('7z', stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=True)
|
||||||
if rarExitCode != 0 and rarExitCode != 1 and rarExitCode != 7:
|
process.communicate()
|
||||||
print('ERROR: UnRAR is missing!')
|
if process.returncode != 0 and process.returncode != 7:
|
||||||
exit(1)
|
print('ERROR: 7z is missing!')
|
||||||
elif source.endswith('.CB7') or source.endswith('.7Z'):
|
|
||||||
sevenzaExitCode = Popen('7za', stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=True)
|
|
||||||
sevenzaExitCode = sevenzaExitCode.wait()
|
|
||||||
if sevenzaExitCode != 0 and sevenzaExitCode != 7:
|
|
||||||
print('ERROR: 7za is missing!')
|
|
||||||
exit(1)
|
exit(1)
|
||||||
if options.format == 'MOBI':
|
if options.format == 'MOBI':
|
||||||
kindleGenExitCode = Popen('kindlegen -locale en', stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=True)
|
kindleGenExitCode = Popen('kindlegen -locale en', stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=True)
|
||||||
if kindleGenExitCode.wait() != 0:
|
kindleGenExitCode.communicate()
|
||||||
|
if kindleGenExitCode.returncode != 0:
|
||||||
print('ERROR: KindleGen is missing!')
|
print('ERROR: KindleGen is missing!')
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
@@ -1104,15 +1141,15 @@ def makeBook(source, qtgui=None):
|
|||||||
getComicInfo(os.path.join(path, "OEBPS", "Images"), source)
|
getComicInfo(os.path.join(path, "OEBPS", "Images"), source)
|
||||||
detectCorruption(os.path.join(path, "OEBPS", "Images"), source)
|
detectCorruption(os.path.join(path, "OEBPS", "Images"), source)
|
||||||
if options.webtoon:
|
if options.webtoon:
|
||||||
if image.ProfileData.Profiles[options.profile][1][1] > 1024:
|
y = image.ProfileData.Profiles[options.profile][1][1]
|
||||||
y = 1024
|
|
||||||
else:
|
|
||||||
y = image.ProfileData.Profiles[options.profile][1][1]
|
|
||||||
comic2panel.main(['-y ' + str(y), '-i', '-m', path], qtgui)
|
comic2panel.main(['-y ' + str(y), '-i', '-m', path], qtgui)
|
||||||
print("Processing images...")
|
if options.noprocessing:
|
||||||
if GUI:
|
print("Do not process image, ignore any profil or processing option")
|
||||||
GUI.progressBarTick.emit('Processing images')
|
else:
|
||||||
imgDirectoryProcessing(os.path.join(path, "OEBPS", "Images"))
|
print("Processing images...")
|
||||||
|
if GUI:
|
||||||
|
GUI.progressBarTick.emit('Processing images')
|
||||||
|
imgDirectoryProcessing(os.path.join(path, "OEBPS", "Images"))
|
||||||
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'))
|
||||||
@@ -1156,7 +1193,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')
|
||||||
@@ -1187,7 +1229,8 @@ def makeBook(source, qtgui=None):
|
|||||||
|
|
||||||
|
|
||||||
def makeMOBIFix(item, uuid):
|
def makeMOBIFix(item, uuid):
|
||||||
os.remove(item)
|
if not options.keep_epub:
|
||||||
|
os.remove(item)
|
||||||
mobiPath = item.replace('.epub', '.mobi')
|
mobiPath = item.replace('.epub', '.mobi')
|
||||||
move(mobiPath, mobiPath + '_toclean')
|
move(mobiPath, mobiPath + '_toclean')
|
||||||
try:
|
try:
|
||||||
@@ -1227,7 +1270,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
|
||||||
@@ -1248,7 +1292,7 @@ def makeMOBI(work, qtgui=None):
|
|||||||
threadNumber = 1
|
threadNumber = 1
|
||||||
elif 2 < availableMemory <= 4:
|
elif 2 < availableMemory <= 4:
|
||||||
threadNumber = 2
|
threadNumber = 2
|
||||||
elif 4 < availableMemory <= 8:
|
elif 4 < availableMemory:
|
||||||
threadNumber = 4
|
threadNumber = 4
|
||||||
else:
|
else:
|
||||||
threadNumber = None
|
threadNumber = None
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
||||||
# Copyright (c) 2013-2018 Pawel Jastrzebski <pawelj@iosphe.re>
|
# Copyright (c) 2013-2019 Pawel Jastrzebski <pawelj@iosphe.re>
|
||||||
#
|
#
|
||||||
# Permission to use, copy, modify, and/or distribute this software for
|
# Permission to use, copy, modify, and/or distribute this software for
|
||||||
# any purpose with or without fee is hereby granted, provided that the
|
# any purpose with or without fee is hereby granted, provided that the
|
||||||
@@ -57,9 +57,8 @@ def mergeDirectory(work):
|
|||||||
if len(images) > 0:
|
if len(images) > 0:
|
||||||
targetWidth = max(set(sizes), key=sizes.count)
|
targetWidth = max(set(sizes), key=sizes.count)
|
||||||
for i in images:
|
for i in images:
|
||||||
if i[1] <= targetWidth:
|
targetHeight += i[2]
|
||||||
targetHeight += i[2]
|
imagesValid.append(i[0])
|
||||||
imagesValid.append(i[0])
|
|
||||||
# Silently drop directories that contain too many images
|
# Silently drop directories that contain too many images
|
||||||
# 131072 = GIMP_MAX_IMAGE_SIZE / 4
|
# 131072 = GIMP_MAX_IMAGE_SIZE / 4
|
||||||
if targetHeight > 131072:
|
if targetHeight > 131072:
|
||||||
@@ -68,8 +67,10 @@ def mergeDirectory(work):
|
|||||||
y = 0
|
y = 0
|
||||||
for i in imagesValid:
|
for i in imagesValid:
|
||||||
img = Image.open(i).convert('RGB')
|
img = Image.open(i).convert('RGB')
|
||||||
if img.size[0] < targetWidth:
|
if img.size[0] < targetWidth or img.size[0] > targetWidth:
|
||||||
img = ImageOps.fit(img, (targetWidth, img.size[1]), method=Image.BICUBIC, centering=(0.5, 0.5))
|
widthPercent = (targetWidth / float(img.size[0]))
|
||||||
|
heightSize = int((float(img.size[1]) * float(widthPercent)))
|
||||||
|
img = ImageOps.fit(img, (targetWidth, heightSize), method=Image.BICUBIC, centering=(0.5, 0.5))
|
||||||
result.paste(img, (0, y))
|
result.paste(img, (0, y))
|
||||||
y += img.size[1]
|
y += img.size[1]
|
||||||
os.remove(i)
|
os.remove(i)
|
||||||
@@ -100,6 +101,8 @@ def splitImage(work):
|
|||||||
name = work[1]
|
name = work[1]
|
||||||
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.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
|
||||||
@@ -113,11 +116,16 @@ def splitImage(work):
|
|||||||
panelDetected = False
|
panelDetected = False
|
||||||
panels = []
|
panels = []
|
||||||
while yWork < heightImg:
|
while yWork < heightImg:
|
||||||
tmpImg = imgProcess.crop([0, yWork, widthImg, 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
|
||||||
panelY1 = yWork - 2
|
panelY1 = yWork - 2
|
||||||
|
if heightImg - yWork <= 5:
|
||||||
|
if not solid and panelDetected:
|
||||||
|
panelY2 = heightImg
|
||||||
|
panelDetected = False
|
||||||
|
panels.append((panelY1, panelY2, panelY2 - panelY1))
|
||||||
if solid and panelDetected:
|
if solid and panelDetected:
|
||||||
panelDetected = False
|
panelDetected = False
|
||||||
panelY2 = yWork + 6
|
panelY2 = yWork + 6
|
||||||
|
|||||||
92
kindlecomicconverter/comicarchive.py
Normal file
92
kindlecomicconverter/comicarchive.py
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
||||||
|
# Copyright (c) 2013-2019 Pawel Jastrzebski <pawelj@iosphe.re>
|
||||||
|
#
|
||||||
|
# Permission to use, copy, modify, and/or distribute this software for
|
||||||
|
# any purpose with or without fee is hereby granted, provided that the
|
||||||
|
# above copyright notice and this permission notice appear in all
|
||||||
|
# copies.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||||
|
# WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||||
|
# WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
||||||
|
# AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
# DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
|
||||||
|
# OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||||
|
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
|
# PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
#
|
||||||
|
|
||||||
|
import os
|
||||||
|
from psutil import Popen
|
||||||
|
from shutil import move
|
||||||
|
from subprocess import STDOUT, PIPE
|
||||||
|
from xml.dom.minidom import parseString
|
||||||
|
from xml.parsers.expat import ExpatError
|
||||||
|
|
||||||
|
|
||||||
|
class ComicArchive:
|
||||||
|
def __init__(self, filepath):
|
||||||
|
self.filepath = filepath
|
||||||
|
self.type = None
|
||||||
|
if not os.path.isfile(self.filepath):
|
||||||
|
raise OSError('File not found.')
|
||||||
|
process = Popen('7z l -y -p1 "' + self.filepath + '"', stderr=STDOUT, stdout=PIPE, stdin=PIPE, shell=True)
|
||||||
|
for line in process.stdout:
|
||||||
|
if b'Type =' in line:
|
||||||
|
self.type = line.rstrip().decode().split(' = ')[1].upper()
|
||||||
|
break
|
||||||
|
process.communicate()
|
||||||
|
if process.returncode != 0:
|
||||||
|
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()
|
||||||
|
print(self.type)
|
||||||
|
break
|
||||||
|
if(self.type != 'RAR'):
|
||||||
|
raise OSError('Archive is corrupted or encrypted.')
|
||||||
|
elif self.type not in ['7Z', 'RAR', 'RAR5', 'ZIP']:
|
||||||
|
raise OSError('Unsupported archive format.')
|
||||||
|
|
||||||
|
def extract(self, targetdir):
|
||||||
|
if not os.path.isdir(targetdir):
|
||||||
|
raise OSError('Target directory don\'t exist.')
|
||||||
|
process = Popen('7z x -y -xr!__MACOSX -xr!.DS_Store -xr!thumbs.db -xr!Thumbs.db -o"' + targetdir + '" "' +
|
||||||
|
self.filepath + '"', stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=True)
|
||||||
|
process.communicate()
|
||||||
|
if process.returncode != 0:
|
||||||
|
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.')
|
||||||
|
tdir = os.listdir(targetdir)
|
||||||
|
if 'ComicInfo.xml' in tdir:
|
||||||
|
tdir.remove('ComicInfo.xml')
|
||||||
|
if len(tdir) == 1 and os.path.isdir(os.path.join(targetdir, tdir[0])):
|
||||||
|
for f in os.listdir(os.path.join(targetdir, tdir[0])):
|
||||||
|
move(os.path.join(targetdir, tdir[0], f), targetdir)
|
||||||
|
os.rmdir(os.path.join(targetdir, tdir[0]))
|
||||||
|
return targetdir
|
||||||
|
|
||||||
|
def addFile(self, sourcefile):
|
||||||
|
if self.type in ['RAR', 'RAR5']:
|
||||||
|
raise NotImplementedError
|
||||||
|
process = Popen('7z a -y "' + self.filepath + '" "' + sourcefile + '"',
|
||||||
|
stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=True)
|
||||||
|
process.communicate()
|
||||||
|
if process.returncode != 0:
|
||||||
|
raise OSError('Failed to add the file.')
|
||||||
|
|
||||||
|
def extractMetadata(self):
|
||||||
|
process = Popen('7z x -y -so "' + self.filepath + '" ComicInfo.xml',
|
||||||
|
stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=True)
|
||||||
|
xml = process.communicate()
|
||||||
|
if process.returncode != 0:
|
||||||
|
raise OSError('Failed to extract archive.')
|
||||||
|
try:
|
||||||
|
return parseString(xml[0])
|
||||||
|
except ExpatError:
|
||||||
|
return None
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Based on initial version of DualMetaFix. Copyright (C) 2013 Kevin Hendricks
|
# Based on initial version of DualMetaFix. Copyright (C) 2013 Kevin Hendricks
|
||||||
# Changes for KCC Copyright (C) 2014-2018 Pawel Jastrzebski <pawelj@iosphe.re>
|
# Changes for KCC Copyright (C) 2014-2019 Pawel Jastrzebski <pawelj@iosphe.re>
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -24,6 +24,7 @@ import shutil
|
|||||||
class DualMetaFixException(Exception):
|
class DualMetaFixException(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
# palm database offset constants
|
# palm database offset constants
|
||||||
number_of_pdb_records = 76
|
number_of_pdb_records = 76
|
||||||
first_pdb_record = 78
|
first_pdb_record = 78
|
||||||
@@ -142,14 +143,12 @@ class DualMobiMetaFix:
|
|||||||
self.datain_rec0 = readsection(self.datain, 0)
|
self.datain_rec0 = readsection(self.datain, 0)
|
||||||
|
|
||||||
# in the first mobi header
|
# in the first mobi header
|
||||||
# add 501 to "EBOK", add 113 as asin, add 504 as asin
|
# add 501 to "EBOK", add 113 as asin
|
||||||
rec0 = self.datain_rec0
|
rec0 = self.datain_rec0
|
||||||
rec0 = del_exth(rec0, 501)
|
rec0 = del_exth(rec0, 501)
|
||||||
rec0 = del_exth(rec0, 113)
|
rec0 = del_exth(rec0, 113)
|
||||||
rec0 = del_exth(rec0, 504)
|
|
||||||
rec0 = add_exth(rec0, 501, b'EBOK')
|
rec0 = add_exth(rec0, 501, b'EBOK')
|
||||||
rec0 = add_exth(rec0, 113, asin)
|
rec0 = add_exth(rec0, 113, asin)
|
||||||
rec0 = add_exth(rec0, 504, asin)
|
|
||||||
replacesection(self.datain, 0, rec0)
|
replacesection(self.datain, 0, rec0)
|
||||||
|
|
||||||
ver = getint(self.datain_rec0, mobi_version)
|
ver = getint(self.datain_rec0, mobi_version)
|
||||||
@@ -171,14 +170,12 @@ class DualMobiMetaFix:
|
|||||||
self.datain_kfrec0 = readsection(self.datain, datain_kf8)
|
self.datain_kfrec0 = readsection(self.datain, datain_kf8)
|
||||||
|
|
||||||
# in the second header
|
# in the second header
|
||||||
# add 501 to "EBOK", add 113 as asin, add 504 as asin
|
# add 501 to "EBOK", add 113 as asin
|
||||||
rec0 = self.datain_kfrec0
|
rec0 = self.datain_kfrec0
|
||||||
rec0 = del_exth(rec0, 501)
|
rec0 = del_exth(rec0, 501)
|
||||||
rec0 = del_exth(rec0, 113)
|
rec0 = del_exth(rec0, 113)
|
||||||
rec0 = del_exth(rec0, 504)
|
|
||||||
rec0 = add_exth(rec0, 501, b'EBOK')
|
rec0 = add_exth(rec0, 501, b'EBOK')
|
||||||
rec0 = add_exth(rec0, 113, asin)
|
rec0 = add_exth(rec0, 113, asin)
|
||||||
rec0 = add_exth(rec0, 504, asin)
|
|
||||||
replacesection(self.datain, datain_kf8, rec0)
|
replacesection(self.datain, datain_kf8, rec0)
|
||||||
|
|
||||||
self.datain.flush()
|
self.datain.flush()
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
# Copyright (C) 2011 Stanislav (proDOOMman) Kosolapov <prodoomman@gmail.com>
|
# Copyright (C) 2011 Stanislav (proDOOMman) Kosolapov <prodoomman@gmail.com>
|
||||||
# Copyright (c) 2016 Alberto Planas <aplanas@gmail.com>
|
# Copyright (c) 2016 Alberto Planas <aplanas@gmail.com>
|
||||||
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
||||||
# Copyright (c) 2013-2018 Pawel Jastrzebski <pawelj@iosphe.re>
|
# Copyright (c) 2013-2019 Pawel Jastrzebski <pawelj@iosphe.re>
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -18,14 +18,11 @@
|
|||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
import io
|
||||||
import os
|
import os
|
||||||
from io import BytesIO
|
import mozjpeg_lossless_optimization
|
||||||
from urllib.request import Request, urlopen
|
|
||||||
from urllib.parse import quote
|
|
||||||
from PIL import Image, ImageOps, ImageStat, ImageChops, ImageFilter
|
from PIL import Image, ImageOps, ImageStat, ImageChops, ImageFilter
|
||||||
from .shared import md5Checksum
|
from .shared import md5Checksum
|
||||||
from . import __version__
|
|
||||||
|
|
||||||
|
|
||||||
class ProfileData:
|
class ProfileData:
|
||||||
@@ -81,13 +78,16 @@ class ProfileData:
|
|||||||
|
|
||||||
Profiles = {
|
Profiles = {
|
||||||
'K1': ("Kindle 1", (600, 670), Palette4, 1.8),
|
'K1': ("Kindle 1", (600, 670), Palette4, 1.8),
|
||||||
|
'K11': ("Kindle 11", (1072, 1448), Palette16, 1.8),
|
||||||
'K2': ("Kindle 2", (600, 670), Palette15, 1.8),
|
'K2': ("Kindle 2", (600, 670), Palette15, 1.8),
|
||||||
'K34': ("Kindle Keyboard/Touch", (600, 800), Palette16, 1.8),
|
'K34': ("Kindle Keyboard/Touch", (600, 800), Palette16, 1.8),
|
||||||
'K578': ("Kindle", (600, 800), Palette16, 1.8),
|
'K578': ("Kindle", (600, 800), Palette16, 1.8),
|
||||||
'KDX': ("Kindle DX/DXG", (824, 1000), Palette16, 1.8),
|
'KDX': ("Kindle DX/DXG", (824, 1000), Palette16, 1.8),
|
||||||
'KPW': ("Kindle Paperwhite 1/2", (758, 1024), Palette16, 1.8),
|
'KPW': ("Kindle Paperwhite 1/2", (758, 1024), Palette16, 1.8),
|
||||||
'KV': ("Kindle Paperwhite 3/Voyage/Oasis", (1072, 1448), Palette16, 1.8),
|
'KV': ("Kindle Paperwhite 3/4/Voyage/Oasis", (1072, 1448), Palette16, 1.8),
|
||||||
'KO': ("Kindle Oasis 2", (1264, 1680), Palette16, 1.8),
|
'KPW5': ("Kindle Paperwhite 5/Signature Edition", (1236, 1648), Palette16, 1.8),
|
||||||
|
'KO': ("Kindle Oasis 2/3", (1264, 1680), Palette16, 1.8),
|
||||||
|
'KS': ("Kindle Scribe", (1860, 2480), Palette16, 1.8),
|
||||||
'KoMT': ("Kobo Mini/Touch", (600, 800), Palette16, 1.8),
|
'KoMT': ("Kobo Mini/Touch", (600, 800), Palette16, 1.8),
|
||||||
'KoG': ("Kobo Glo", (768, 1024), Palette16, 1.8),
|
'KoG': ("Kobo Glo", (768, 1024), Palette16, 1.8),
|
||||||
'KoGHD': ("Kobo Glo HD", (1072, 1448), Palette16, 1.8),
|
'KoGHD': ("Kobo Glo HD", (1072, 1448), Palette16, 1.8),
|
||||||
@@ -95,12 +95,19 @@ class ProfileData:
|
|||||||
'KoAHD': ("Kobo Aura HD", (1080, 1440), Palette16, 1.8),
|
'KoAHD': ("Kobo Aura HD", (1080, 1440), Palette16, 1.8),
|
||||||
'KoAH2O': ("Kobo Aura H2O", (1080, 1430), Palette16, 1.8),
|
'KoAH2O': ("Kobo Aura H2O", (1080, 1430), Palette16, 1.8),
|
||||||
'KoAO': ("Kobo Aura ONE", (1404, 1872), Palette16, 1.8),
|
'KoAO': ("Kobo Aura ONE", (1404, 1872), Palette16, 1.8),
|
||||||
|
'KoN': ("Kobo Nia", (758, 1024), Palette16, 1.8),
|
||||||
|
'KoC': ("Kobo Clara HD/Kobo Clara 2E", (1072, 1448), Palette16, 1.8),
|
||||||
|
'KoL': ("Kobo Libra H2O/Kobo Libra 2", (1264, 1680), Palette16, 1.8),
|
||||||
|
'KoF': ("Kobo Forma", (1440, 1920), Palette16, 1.8),
|
||||||
|
'KoS': ("Kobo Sage", (1440, 1920), Palette16, 1.8),
|
||||||
|
'KoE': ("Kobo Elipsa", (1404, 1872), Palette16, 1.8),
|
||||||
'OTHER': ("Other", (0, 0), Palette16, 1.8),
|
'OTHER': ("Other", (0, 0), Palette16, 1.8),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class ComicPageParser:
|
class ComicPageParser:
|
||||||
def __init__(self, source, options):
|
def __init__(self, source, options):
|
||||||
|
Image.MAX_IMAGE_PIXELS = int(2048 * 2048 * 2048 // 4 // 3)
|
||||||
self.opt = options
|
self.opt = options
|
||||||
self.source = source
|
self.source = source
|
||||||
self.size = self.opt.profileData[1]
|
self.size = self.opt.profileData[1]
|
||||||
@@ -108,6 +115,9 @@ 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()
|
||||||
|
# backwards compatibility for Pillow >9.1.0
|
||||||
|
if not hasattr(Image, 'Resampling'):
|
||||||
|
Image.Resampling = Image
|
||||||
self.splitCheck()
|
self.splitCheck()
|
||||||
|
|
||||||
def getImageHistogram(self, image):
|
def getImageHistogram(self, image):
|
||||||
@@ -122,9 +132,22 @@ class ComicPageParser:
|
|||||||
def splitCheck(self):
|
def splitCheck(self):
|
||||||
width, height = self.image.size
|
width, height = self.image.size
|
||||||
dstwidth, dstheight = self.size
|
dstwidth, dstheight = self.size
|
||||||
if (width > height) != (dstwidth > dstheight) and width <= dstheight and height <= dstwidth \
|
if self.opt.maximizestrips:
|
||||||
|
leftbox = (0, 0, int(width / 2), height)
|
||||||
|
rightbox = (int(width / 2), 0, width, height)
|
||||||
|
if self.opt.righttoleft:
|
||||||
|
pageone = self.image.crop(rightbox)
|
||||||
|
pagetwo = self.image.crop(leftbox)
|
||||||
|
else:
|
||||||
|
pageone = self.image.crop(leftbox)
|
||||||
|
pagetwo = self.image.crop(rightbox)
|
||||||
|
new_image = Image.new("RGB", (int(width / 2), int(height*2)))
|
||||||
|
new_image.paste(pageone, (0, 0))
|
||||||
|
new_image.paste(pagetwo, (0, height))
|
||||||
|
self.payload.append(['N', self.source, new_image, self.color, self.fill])
|
||||||
|
elif (width > height) != (dstwidth > dstheight) and width <= dstheight and height <= dstwidth \
|
||||||
and not self.opt.webtoon and self.opt.splitter == 1:
|
and not self.opt.webtoon and self.opt.splitter == 1:
|
||||||
self.payload.append(['R', self.source, self.image.rotate(90, Image.BICUBIC, True), self.color, self.fill])
|
self.payload.append(['R', self.source, self.image.rotate(90, Image.Resampling.BICUBIC, True), self.color, self.fill])
|
||||||
elif (width > height) != (dstwidth > dstheight) and not self.opt.webtoon:
|
elif (width > height) != (dstwidth > dstheight) and not self.opt.webtoon:
|
||||||
if self.opt.splitter != 1:
|
if self.opt.splitter != 1:
|
||||||
if width > height:
|
if width > height:
|
||||||
@@ -142,7 +165,7 @@ class ComicPageParser:
|
|||||||
self.payload.append(['S1', self.source, pageone, self.color, self.fill])
|
self.payload.append(['S1', self.source, pageone, self.color, self.fill])
|
||||||
self.payload.append(['S2', self.source, pagetwo, self.color, self.fill])
|
self.payload.append(['S2', self.source, pagetwo, self.color, self.fill])
|
||||||
if self.opt.splitter > 0:
|
if self.opt.splitter > 0:
|
||||||
self.payload.append(['R', self.source, self.image.rotate(90, Image.BICUBIC, True),
|
self.payload.append(['R', self.source, self.image.rotate(90, Image.Resampling.BICUBIC, True),
|
||||||
self.color, self.fill])
|
self.color, self.fill])
|
||||||
else:
|
else:
|
||||||
self.payload.append(['N', self.source, self.image, self.color, self.fill])
|
self.payload.append(['N', self.source, self.image, self.color, self.fill])
|
||||||
@@ -228,6 +251,9 @@ class ComicPage:
|
|||||||
self.targetPath = os.path.join(path[0], os.path.splitext(path[1])[0]) + '-KCC-B'
|
self.targetPath = os.path.join(path[0], os.path.splitext(path[1])[0]) + '-KCC-B'
|
||||||
elif 'S2' in mode:
|
elif 'S2' in mode:
|
||||||
self.targetPath = os.path.join(path[0], os.path.splitext(path[1])[0]) + '-KCC-C'
|
self.targetPath = os.path.join(path[0], os.path.splitext(path[1])[0]) + '-KCC-C'
|
||||||
|
# backwards compatibility for Pillow >9.1.0
|
||||||
|
if not hasattr(Image, 'Resampling'):
|
||||||
|
Image.Resampling = Image
|
||||||
|
|
||||||
def saveToDir(self):
|
def saveToDir(self):
|
||||||
try:
|
try:
|
||||||
@@ -243,7 +269,15 @@ class ComicPage:
|
|||||||
self.image.save(self.targetPath, 'PNG', optimize=1)
|
self.image.save(self.targetPath, 'PNG', optimize=1)
|
||||||
else:
|
else:
|
||||||
self.targetPath += '.jpg'
|
self.targetPath += '.jpg'
|
||||||
self.image.save(self.targetPath, 'JPEG', optimize=1, quality=85)
|
if self.opt.mozjpeg:
|
||||||
|
with io.BytesIO() as output:
|
||||||
|
self.image.save(output, format="JPEG", optimize=1, quality=85)
|
||||||
|
input_jpeg_bytes = output.getvalue()
|
||||||
|
output_jpeg_bytes = mozjpeg_lossless_optimization.optimize(input_jpeg_bytes)
|
||||||
|
with open(self.targetPath, "wb") as output_jpeg_file:
|
||||||
|
output_jpeg_file.write(output_jpeg_bytes)
|
||||||
|
else:
|
||||||
|
self.image.save(self.targetPath, 'JPEG', optimize=1, quality=85)
|
||||||
return [md5Checksum(self.targetPath), flags, self.orgPath]
|
return [md5Checksum(self.targetPath), flags, self.orgPath]
|
||||||
except IOError as err:
|
except IOError as err:
|
||||||
raise RuntimeError('Cannot save image. ' + str(err))
|
raise RuntimeError('Cannot save image. ' + str(err))
|
||||||
@@ -257,7 +291,7 @@ class ComicPage:
|
|||||||
if gamma == 1.0:
|
if gamma == 1.0:
|
||||||
self.image = ImageOps.autocontrast(self.image)
|
self.image = ImageOps.autocontrast(self.image)
|
||||||
else:
|
else:
|
||||||
self.image = ImageOps.autocontrast(Image.eval(self.image, lambda a: 255 * (a / 255.) ** gamma))
|
self.image = ImageOps.autocontrast(Image.eval(self.image, lambda a: int(255 * (a / 255.) ** gamma)))
|
||||||
|
|
||||||
def quantizeImage(self):
|
def quantizeImage(self):
|
||||||
colors = len(self.palette) // 3
|
colors = len(self.palette) // 3
|
||||||
@@ -272,10 +306,11 @@ class ComicPage:
|
|||||||
|
|
||||||
def resizeImage(self):
|
def resizeImage(self):
|
||||||
if self.image.size[0] <= self.size[0] and self.image.size[1] <= self.size[1]:
|
if self.image.size[0] <= self.size[0] and self.image.size[1] <= self.size[1]:
|
||||||
method = Image.BICUBIC
|
method = Image.Resampling.BICUBIC
|
||||||
else:
|
else:
|
||||||
method = Image.LANCZOS
|
method = Image.Resampling.LANCZOS
|
||||||
if self.opt.stretch or (self.opt.kfx and ('-KCC-B' in self.targetPath or '-KCC-C' in self.targetPath)):
|
if self.opt.stretch:
|
||||||
|
# if self.opt.stretch or (self.opt.kfx and ('-KCC-B' in self.targetPath or '-KCC-C' in self.targetPath)):
|
||||||
self.image = self.image.resize(self.size, method)
|
self.image = self.image.resize(self.size, method)
|
||||||
elif self.image.size[0] <= self.size[0] and self.image.size[1] <= self.size[1] and not self.opt.upscale:
|
elif self.image.size[0] <= self.size[0] and self.image.size[1] <= self.size[1] and not self.opt.upscale:
|
||||||
if self.opt.format == 'CBZ' or self.opt.kfx:
|
if self.opt.format == 'CBZ' or self.opt.kfx:
|
||||||
@@ -283,7 +318,7 @@ class ComicPage:
|
|||||||
borderh = int((self.size[1] - self.image.size[1]) / 2)
|
borderh = int((self.size[1] - self.image.size[1]) / 2)
|
||||||
self.image = ImageOps.expand(self.image, border=(borderw, borderh), fill=self.fill)
|
self.image = ImageOps.expand(self.image, border=(borderw, borderh), fill=self.fill)
|
||||||
if self.image.size[0] != self.size[0] or self.image.size[1] != self.size[1]:
|
if self.image.size[0] != self.size[0] or self.image.size[1] != self.size[1]:
|
||||||
self.image = ImageOps.fit(self.image, self.size, method=Image.BICUBIC, centering=(0.5, 0.5))
|
self.image = ImageOps.fit(self.image, self.size, method=Image.Resampling.BICUBIC, centering=(0.5, 0.5))
|
||||||
else:
|
else:
|
||||||
if self.opt.format == 'CBZ' or self.opt.kfx:
|
if self.opt.format == 'CBZ' or self.opt.kfx:
|
||||||
ratioDev = float(self.size[0]) / float(self.size[1])
|
ratioDev = float(self.size[0]) / float(self.size[1])
|
||||||
@@ -299,7 +334,7 @@ class ComicPage:
|
|||||||
wsize = int((float(self.image.size[0]) * float(hpercent)))
|
wsize = int((float(self.image.size[0]) * float(hpercent)))
|
||||||
self.image = self.image.resize((wsize, self.size[1]), method)
|
self.image = self.image.resize((wsize, self.size[1]), method)
|
||||||
if self.image.size[0] > self.size[0] or self.image.size[1] > self.size[1]:
|
if self.image.size[0] > self.size[0] or self.image.size[1] > self.size[1]:
|
||||||
self.image.thumbnail(self.size, Image.LANCZOS)
|
self.image.thumbnail(self.size, Image.Resampling.LANCZOS)
|
||||||
|
|
||||||
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]
|
||||||
@@ -315,7 +350,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:
|
||||||
@@ -324,16 +365,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:
|
||||||
@@ -345,15 +388,10 @@ class Cover:
|
|||||||
self.tomeid = 1
|
self.tomeid = 1
|
||||||
else:
|
else:
|
||||||
self.tomeid = tomeid
|
self.tomeid = tomeid
|
||||||
if self.tomeid in self.options.remoteCovers:
|
self.image = Image.open(source)
|
||||||
try:
|
# backwards compatibility for Pillow >9.1.0
|
||||||
source = urlopen(Request(quote(self.options.remoteCovers[self.tomeid]).replace('%3A', ':', 1),
|
if not hasattr(Image, 'Resampling'):
|
||||||
headers={'User-Agent': 'KindleComicConverter/' + __version__})).read()
|
Image.Resampling = Image
|
||||||
self.image = Image.open(BytesIO(source))
|
|
||||||
except Exception:
|
|
||||||
self.image = Image.open(source)
|
|
||||||
else:
|
|
||||||
self.image = Image.open(source)
|
|
||||||
self.process()
|
self.process()
|
||||||
|
|
||||||
def process(self):
|
def process(self):
|
||||||
@@ -361,17 +399,17 @@ class Cover:
|
|||||||
self.image = ImageOps.autocontrast(self.image)
|
self.image = ImageOps.autocontrast(self.image)
|
||||||
if not self.options.forcecolor:
|
if not self.options.forcecolor:
|
||||||
self.image = self.image.convert('L')
|
self.image = self.image.convert('L')
|
||||||
self.image.thumbnail(self.options.profileData[1], Image.LANCZOS)
|
self.image.thumbnail(self.options.profileData[1], Image.Resampling.LANCZOS)
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
try:
|
try:
|
||||||
self.image.save(self.target, "JPEG", optimize=1, quality=85)
|
self.image.save(self.target, "JPEG", optimize=1, quality=85)
|
||||||
except IOError:
|
except IOError:
|
||||||
raise RuntimeError('Failed to process downloaded cover.')
|
raise RuntimeError('Failed to save cover.')
|
||||||
|
|
||||||
def saveToKindle(self, kindle, asin):
|
def saveToKindle(self, kindle, asin):
|
||||||
self.image = self.image.resize((300, 470), Image.ANTIALIAS)
|
self.image = self.image.resize((300, 470), Image.Resampling.LANCZOS)
|
||||||
try:
|
try:
|
||||||
self.image.save(os.path.join(kindle.path.split('documents')[0], 'system', 'thumbnails',
|
self.image.save(os.path.join(kindle.path.split('documents')[0], 'system', 'thumbnails',
|
||||||
'thumbnail_' + asin + '_EBOK_portrait.jpg'), 'JPEG', optimize=1, quality=85)
|
'thumbnail_' + asin + '_EBOK_portrait.jpg'), 'JPEG', optimize=1, quality=85)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Copyright (c) 2013-2018 Pawel Jastrzebski <pawelj@iosphe.re>
|
# Copyright (c) 2013-2019 Pawel Jastrzebski <pawelj@iosphe.re>
|
||||||
#
|
#
|
||||||
# Permission to use, copy, modify, and/or distribute this software for
|
# Permission to use, copy, modify, and/or distribute this software for
|
||||||
# any purpose with or without fee is hereby granted, provided that the
|
# any purpose with or without fee is hereby granted, provided that the
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Copyright (c) 2013-2018 Pawel Jastrzebski <pawelj@iosphe.re>
|
# Copyright (c) 2013-2019 Pawel Jastrzebski <pawelj@iosphe.re>
|
||||||
#
|
#
|
||||||
# Permission to use, copy, modify, and/or distribute this software for
|
# Permission to use, copy, modify, and/or distribute this software for
|
||||||
# any purpose with or without fee is hereby granted, provided that the
|
# any purpose with or without fee is hereby granted, provided that the
|
||||||
@@ -18,14 +18,9 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
from xml.dom.minidom import parse, Document
|
from xml.dom.minidom import parse, Document
|
||||||
from re import compile
|
|
||||||
from zipfile import is_zipfile, ZipFile, ZIP_DEFLATED
|
|
||||||
from subprocess import STDOUT, PIPE
|
|
||||||
from psutil import Popen
|
|
||||||
from tempfile import mkdtemp
|
from tempfile import mkdtemp
|
||||||
from shutil import rmtree
|
from shutil import rmtree
|
||||||
from .shared import removeFromZIP, check7ZFile as is_7zfile
|
from . import comicarchive
|
||||||
from . import rarfile
|
|
||||||
|
|
||||||
|
|
||||||
class MetadataParser:
|
class MetadataParser:
|
||||||
@@ -39,50 +34,20 @@ class MetadataParser:
|
|||||||
'Inkers': [],
|
'Inkers': [],
|
||||||
'Colorists': [],
|
'Colorists': [],
|
||||||
'Summary': '',
|
'Summary': '',
|
||||||
'MUid': '',
|
|
||||||
'Bookmarks': []}
|
'Bookmarks': []}
|
||||||
self.rawdata = None
|
self.rawdata = None
|
||||||
self.compressor = 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):
|
||||||
self.rawdata = parse(self.source)
|
self.rawdata = parse(self.source)
|
||||||
self.parseXML()
|
|
||||||
elif not self.source.endswith('.xml'):
|
elif not self.source.endswith('.xml'):
|
||||||
if is_zipfile(self.source):
|
try:
|
||||||
self.compressor = 'zip'
|
cbx = comicarchive.ComicArchive(self.source)
|
||||||
with ZipFile(self.source) as zip_file:
|
self.rawdata = cbx.extractMetadata()
|
||||||
for member in zip_file.namelist():
|
self.format = cbx.type
|
||||||
if member != 'ComicInfo.xml':
|
except OSError as e:
|
||||||
continue
|
raise UserWarning(e.strerror)
|
||||||
with zip_file.open(member) as xml_file:
|
if self.rawdata:
|
||||||
self.rawdata = parse(xml_file)
|
self.parseXML()
|
||||||
elif rarfile.is_rarfile(self.source):
|
|
||||||
self.compressor = 'rar'
|
|
||||||
with rarfile.RarFile(self.source) as rar_file:
|
|
||||||
for member in rar_file.namelist():
|
|
||||||
if member != 'ComicInfo.xml':
|
|
||||||
continue
|
|
||||||
with rar_file.open(member) as xml_file:
|
|
||||||
self.rawdata = parse(xml_file)
|
|
||||||
elif is_7zfile(self.source):
|
|
||||||
self.compressor = '7z'
|
|
||||||
workdir = mkdtemp('', 'KCC-')
|
|
||||||
tmpXML = os.path.join(workdir, 'ComicInfo.xml')
|
|
||||||
output = Popen('7za e "' + self.source + '" ComicInfo.xml -o"' + workdir + '"',
|
|
||||||
stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=True)
|
|
||||||
extracted = False
|
|
||||||
for line in output.stdout:
|
|
||||||
if b"Everything is Ok" in line or b"No files to process" in line:
|
|
||||||
extracted = True
|
|
||||||
if not extracted:
|
|
||||||
rmtree(workdir)
|
|
||||||
raise OSError('Failed to extract 7ZIP file.')
|
|
||||||
if os.path.isfile(tmpXML):
|
|
||||||
self.rawdata = parse(tmpXML)
|
|
||||||
rmtree(workdir)
|
|
||||||
else:
|
|
||||||
raise OSError('Failed to detect archive format.')
|
|
||||||
if self.rawdata:
|
|
||||||
self.parseXML()
|
|
||||||
|
|
||||||
def parseXML(self):
|
def parseXML(self):
|
||||||
if len(self.rawdata.getElementsByTagName('Series')) != 0:
|
if len(self.rawdata.getElementsByTagName('Series')) != 0:
|
||||||
@@ -99,11 +64,6 @@ class MetadataParser:
|
|||||||
self.data[field + 's'].append(person)
|
self.data[field + 's'].append(person)
|
||||||
self.data[field + 's'] = list(set(self.data[field + 's']))
|
self.data[field + 's'] = list(set(self.data[field + 's']))
|
||||||
self.data[field + 's'].sort()
|
self.data[field + 's'].sort()
|
||||||
if len(self.rawdata.getElementsByTagName('ScanInformation')) != 0:
|
|
||||||
coverId = compile('(MCD\\()(\\d+)(\\))')\
|
|
||||||
.search(self.rawdata.getElementsByTagName('ScanInformation')[0].firstChild.nodeValue)
|
|
||||||
if coverId:
|
|
||||||
self.data['MUid'] = coverId.group(2)
|
|
||||||
if len(self.rawdata.getElementsByTagName('Page')) != 0:
|
if len(self.rawdata.getElementsByTagName('Page')) != 0:
|
||||||
for page in self.rawdata.getElementsByTagName('Page'):
|
for page in self.rawdata.getElementsByTagName('Page'):
|
||||||
if 'Bookmark' in page.attributes and 'Image' in page.attributes:
|
if 'Bookmark' in page.attributes and 'Image' in page.attributes:
|
||||||
@@ -116,8 +76,7 @@ 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']]):
|
||||||
['ScanInformation', 'MCD(' + self.data['MUid'] + ')' if self.data['MUid'] else '']):
|
|
||||||
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]:
|
||||||
@@ -138,8 +97,7 @@ 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']]):
|
||||||
['ScanInformation', 'MCD(' + self.data['MUid'] + ')' if self.data['MUid'] else '']):
|
|
||||||
if row[1]:
|
if row[1]:
|
||||||
main = doc.createElement(row[0])
|
main = doc.createElement(row[0])
|
||||||
root.appendChild(main)
|
root.appendChild(main)
|
||||||
@@ -154,20 +112,9 @@ class MetadataParser:
|
|||||||
tmpXML = os.path.join(workdir, 'ComicInfo.xml')
|
tmpXML = os.path.join(workdir, 'ComicInfo.xml')
|
||||||
with open(tmpXML, 'w', encoding='utf-8') as f:
|
with open(tmpXML, 'w', encoding='utf-8') as f:
|
||||||
self.rawdata.writexml(f, encoding='utf-8')
|
self.rawdata.writexml(f, encoding='utf-8')
|
||||||
if is_zipfile(self.source):
|
try:
|
||||||
removeFromZIP(self.source, 'ComicInfo.xml')
|
cbx = comicarchive.ComicArchive(self.source)
|
||||||
with ZipFile(self.source, mode='a', compression=ZIP_DEFLATED) as zip_file:
|
cbx.addFile(tmpXML)
|
||||||
zip_file.write(tmpXML, arcname=tmpXML.split(os.sep)[-1])
|
except OSError as e:
|
||||||
elif rarfile.is_rarfile(self.source):
|
raise UserWarning(e.strerror)
|
||||||
raise NotImplementedError
|
|
||||||
elif is_7zfile(self.source):
|
|
||||||
output = Popen('7za a "' + self.source + '" "' + tmpXML + '"',
|
|
||||||
stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=True)
|
|
||||||
extracted = False
|
|
||||||
for line in output.stdout:
|
|
||||||
if b"Everything is Ok" in line:
|
|
||||||
extracted = True
|
|
||||||
if not extracted:
|
|
||||||
rmtree(workdir)
|
|
||||||
raise OSError('Failed to modify 7ZIP file.')
|
|
||||||
rmtree(workdir)
|
rmtree(workdir)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
||||||
# Copyright (c) 2013-2018 Pawel Jastrzebski <pawelj@iosphe.re>
|
# Copyright (c) 2013-2019 Pawel Jastrzebski <pawelj@iosphe.re>
|
||||||
#
|
#
|
||||||
# Based upon the code snippet by Ned Batchelder
|
# Based upon the code snippet by Ned Batchelder
|
||||||
# (http://nedbatchelder.com/blog/200712/extracting_jpgs_from_pdfs.html)
|
# (http://nedbatchelder.com/blog/200712/extracting_jpgs_from_pdfs.html)
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
||||||
# Copyright (c) 2013-2018 Pawel Jastrzebski <pawelj@iosphe.re>
|
# Copyright (c) 2013-2019 Pawel Jastrzebski <pawelj@iosphe.re>
|
||||||
#
|
#
|
||||||
# Permission to use, copy, modify, and/or distribute this software for
|
# Permission to use, copy, modify, and/or distribute this software for
|
||||||
# any purpose with or without fee is hereby granted, provided that the
|
# any purpose with or without fee is hereby granted, provided that the
|
||||||
@@ -22,9 +22,6 @@ import os
|
|||||||
from hashlib import md5
|
from hashlib import md5
|
||||||
from html.parser import HTMLParser
|
from html.parser import HTMLParser
|
||||||
from distutils.version import StrictVersion
|
from distutils.version import StrictVersion
|
||||||
from shutil import rmtree, copy
|
|
||||||
from tempfile import mkdtemp
|
|
||||||
from zipfile import ZipFile, ZIP_DEFLATED
|
|
||||||
from re import split
|
from re import split
|
||||||
from traceback import format_tb
|
from traceback import format_tb
|
||||||
|
|
||||||
@@ -50,7 +47,7 @@ class HTMLStripper(HTMLParser):
|
|||||||
def getImageFileName(imgfile):
|
def getImageFileName(imgfile):
|
||||||
name, ext = os.path.splitext(imgfile)
|
name, ext = os.path.splitext(imgfile)
|
||||||
ext = ext.lower()
|
ext = ext.lower()
|
||||||
if name.startswith('.') or (ext != '.png' and ext != '.jpg' and ext != '.jpeg' and ext != '.gif'):
|
if (name.startswith('.') and len(name) == 1) or ext not in ['.png', '.jpg', '.jpeg', '.gif', '.webp']:
|
||||||
return None
|
return None
|
||||||
return [name, ext]
|
return [name, ext]
|
||||||
|
|
||||||
@@ -86,38 +83,19 @@ def md5Checksum(fpath):
|
|||||||
return m.hexdigest()
|
return m.hexdigest()
|
||||||
|
|
||||||
|
|
||||||
def check7ZFile(fpath):
|
|
||||||
with open(fpath, 'rb') as fh:
|
|
||||||
header = fh.read(6)
|
|
||||||
return header == b"7z\xbc\xaf'\x1c"
|
|
||||||
|
|
||||||
|
|
||||||
def removeFromZIP(zipfname, *filenames):
|
|
||||||
tempdir = mkdtemp('', 'KCC-')
|
|
||||||
try:
|
|
||||||
tempname = os.path.join(tempdir, 'KCC.zip')
|
|
||||||
with ZipFile(zipfname, 'r') as zipread:
|
|
||||||
with ZipFile(tempname, 'w', compression=ZIP_DEFLATED) as zipwrite:
|
|
||||||
for item in zipread.infolist():
|
|
||||||
if item.filename not in filenames:
|
|
||||||
zipwrite.writestr(item, zipread.read(item.filename))
|
|
||||||
copy(tempname, zipfname)
|
|
||||||
finally:
|
|
||||||
rmtree(tempdir, True)
|
|
||||||
|
|
||||||
|
|
||||||
def sanitizeTrace(traceback):
|
def sanitizeTrace(traceback):
|
||||||
return ''.join(format_tb(traceback))\
|
return ''.join(format_tb(traceback))\
|
||||||
.replace('C:/projects/kcc/', '') \
|
.replace('C:/projects/kcc/', '')\
|
||||||
.replace('c:/projects/kcc/', '') \
|
.replace('c:/projects/kcc/', '')\
|
||||||
.replace('C:/python36-x64/', '')\
|
.replace('C:/python37-x64/', '')\
|
||||||
.replace('c:/python36-x64/', '')\
|
.replace('c:/python37-x64/', '')\
|
||||||
.replace('C:\\projects\\kcc\\', '') \
|
.replace('C:\\projects\\kcc\\', '')\
|
||||||
.replace('c:\\projects\\kcc\\', '') \
|
.replace('c:\\projects\\kcc\\', '')\
|
||||||
.replace('C:\\python36-x64\\', '')\
|
.replace('C:\\python37-x64\\', '')\
|
||||||
.replace('c:\\python36-x64\\', '')
|
.replace('c:\\python37-x64\\', '')
|
||||||
|
|
||||||
|
|
||||||
|
# noinspection PyUnresolvedReferences
|
||||||
def dependencyCheck(level):
|
def dependencyCheck(level):
|
||||||
missing = []
|
missing = []
|
||||||
if level > 2:
|
if level > 2:
|
||||||
@@ -139,17 +117,20 @@ def dependencyCheck(level):
|
|||||||
except ImportError:
|
except ImportError:
|
||||||
missing.append('psutil 5.0.0+')
|
missing.append('psutil 5.0.0+')
|
||||||
try:
|
try:
|
||||||
|
from types import ModuleType
|
||||||
from slugify import __version__ as slugifyVersion
|
from slugify import __version__ as slugifyVersion
|
||||||
|
if isinstance(slugifyVersion, ModuleType):
|
||||||
|
slugifyVersion = slugifyVersion.__version__
|
||||||
if StrictVersion('1.2.1') > StrictVersion(slugifyVersion):
|
if StrictVersion('1.2.1') > StrictVersion(slugifyVersion):
|
||||||
missing.append('python-slugify 1.2.1+')
|
missing.append('python-slugify 1.2.1+')
|
||||||
except ImportError:
|
except ImportError:
|
||||||
missing.append('python-slugify 1.2.1+')
|
missing.append('python-slugify 1.2.1+')
|
||||||
try:
|
try:
|
||||||
from PIL import PILLOW_VERSION as pillowVersion
|
from PIL import __version__ as pillowVersion
|
||||||
if StrictVersion('4.0.0') > StrictVersion(pillowVersion):
|
if StrictVersion('5.2.0') > StrictVersion(pillowVersion):
|
||||||
missing.append('Pillow 4.0.0+')
|
missing.append('Pillow 5.2.0+')
|
||||||
except ImportError:
|
except ImportError:
|
||||||
missing.append('Pillow 4.0.0+')
|
missing.append('Pillow 5.2.0+')
|
||||||
if len(missing) > 0:
|
if len(missing) > 0:
|
||||||
print('ERROR: ' + ', '.join(missing) + ' is not installed!')
|
print('ERROR: ' + ', '.join(missing) + ' is not installed!')
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
||||||
# Copyright (c) 2013-2018 Pawel Jastrzebski <pawelj@iosphe.re>
|
# Copyright (c) 2013-2019 Pawel Jastrzebski <pawelj@iosphe.re>
|
||||||
#
|
#
|
||||||
# Permission to use, copy, modify, and/or distribute this software for
|
# Permission to use, copy, modify, and/or distribute this software for
|
||||||
# any purpose with or without fee is hereby granted, provided that the
|
# any purpose with or without fee is hereby granted, provided that the
|
||||||
@@ -30,15 +30,15 @@ def start():
|
|||||||
os.environ['QT_AUTO_SCREEN_SCALE_FACTOR'] = "1"
|
os.environ['QT_AUTO_SCREEN_SCALE_FACTOR'] = "1"
|
||||||
KCCAplication = KCC_gui.QApplicationMessaging(sys.argv)
|
KCCAplication = KCC_gui.QApplicationMessaging(sys.argv)
|
||||||
if KCCAplication.isRunning():
|
if KCCAplication.isRunning():
|
||||||
if len(sys.argv) > 1:
|
for i in range(1, len(sys.argv)):
|
||||||
KCCAplication.sendMessage(sys.argv[1])
|
KCCAplication.sendMessage(sys.argv[i])
|
||||||
else:
|
else:
|
||||||
KCCAplication.sendMessage('ARISE')
|
KCCAplication.sendMessage('ARISE')
|
||||||
else:
|
else:
|
||||||
KCCWindow = KCC_gui.QMainWindowKCC()
|
KCCWindow = KCC_gui.QMainWindowKCC()
|
||||||
KCCUI = KCC_gui.KCCGUI(KCCAplication, KCCWindow)
|
KCCUI = KCC_gui.KCCGUI(KCCAplication, KCCWindow)
|
||||||
if len(sys.argv) > 1:
|
for i in range(1, len(sys.argv)):
|
||||||
KCCUI.handleMessage(sys.argv[1])
|
KCCUI.handleMessage(sys.argv[i])
|
||||||
sys.exit(KCCAplication.exec_())
|
sys.exit(KCCAplication.exec_())
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
kindlecomicconverter: binary-without-manpage usr/bin/kcc
|
|
||||||
kindlecomicconverter: wrong-name-for-changelog-of-native-package usr/share/doc/kindlecomicconverter/changelog.Debian.gz
|
|
||||||
kindlecomicconverter: file-missing-in-md5sums usr/share/doc/kindlecomicconverter/changelog.Debian.gz
|
|
||||||
kindlecomicconverter: hardening-no-relro usr/bin/kcc
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
[Desktop Entry]
|
|
||||||
Type=Application
|
|
||||||
Version=1.0
|
|
||||||
Name=Kindle Comic Converter
|
|
||||||
GenericName=Kindle Comic Converter
|
|
||||||
Comment=Comic and Manga converter for e-book readers
|
|
||||||
Icon=/usr/share/kindlecomicconverter/comic2ebook.png
|
|
||||||
Exec=/usr/bin/kcc %f
|
|
||||||
Terminal=false
|
|
||||||
Categories=Graphics;
|
|
||||||
MimeType=application/zip;application/x-rar;application/x-7z-compressed;
|
|
||||||
Binary file not shown.
BIN
other/osx/7z
Executable file
BIN
other/osx/7z
Executable file
Binary file not shown.
BIN
other/osx/7z.so
Normal file
BIN
other/osx/7z.so
Normal file
Binary file not shown.
BIN
other/osx/7za
BIN
other/osx/7za
Binary file not shown.
@@ -30,7 +30,7 @@
|
|||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
<string>MacOS/Kindle Comic Converter</string>
|
<string>MacOS/Kindle Comic Converter</string>
|
||||||
<key>CFBundleGetInfoString</key>
|
<key>CFBundleGetInfoString</key>
|
||||||
<string>KindleComicConverter 5.4.5, written 2012-2018 by Ciro Mattia Gonano and Pawel Jastrzebski</string>
|
<string>KindleComicConverter 5.5.2, written 2012-2019 by Ciro Mattia Gonano and Pawel Jastrzebski</string>
|
||||||
<key>CFBundleIconFile</key>
|
<key>CFBundleIconFile</key>
|
||||||
<string>comic2ebook.icns</string>
|
<string>comic2ebook.icns</string>
|
||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
@@ -42,20 +42,20 @@
|
|||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>5.4.5</string>
|
<string>5.5.2</string>
|
||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>????</string>
|
<string>????</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>5.4.5</string>
|
<string>5.5.2</string>
|
||||||
<key>LSEnvironment</key>
|
<key>LSEnvironment</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>PATH</key>
|
<key>PATH</key>
|
||||||
<string>./../Resources:/usr/local/bin:/usr/bin:/bin</string>
|
<string>./../Resources:/Applications/Kindle Comic Creator/Kindle Comic Creator.app/Contents/MacOS:/usr/local/bin:/usr/bin:/bin</string>
|
||||||
</dict>
|
</dict>
|
||||||
<key>LSHasLocalizedDisplayName</key>
|
<key>LSHasLocalizedDisplayName</key>
|
||||||
<false/>
|
<false/>
|
||||||
<key>LSMinimumSystemVersion</key>
|
<key>LSMinimumSystemVersion</key>
|
||||||
<string>10.10.0</string>
|
<string>10.14.0</string>
|
||||||
<key>NSAppleScriptEnabled</key>
|
<key>NSAppleScriptEnabled</key>
|
||||||
<false/>
|
<false/>
|
||||||
<key>NSHumanReadableCopyright</key>
|
<key>NSHumanReadableCopyright</key>
|
||||||
@@ -64,5 +64,9 @@
|
|||||||
<string>MainMenu</string>
|
<string>MainMenu</string>
|
||||||
<key>NSPrincipalClass</key>
|
<key>NSPrincipalClass</key>
|
||||||
<string>NSApplication</string>
|
<string>NSApplication</string>
|
||||||
|
<key>NSRequiresAquaSystemAppearance</key>
|
||||||
|
<string>false</string>
|
||||||
|
<key>NSInitialToolTipDelay</key>
|
||||||
|
<integer>1000</integer>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
BIN
other/osx/Rar.so
Normal file
BIN
other/osx/Rar.so
Normal file
Binary file not shown.
Binary file not shown.
BIN
other/osx/unrar
BIN
other/osx/unrar
Binary file not shown.
BIN
other/windows/7z.dll
Normal file
BIN
other/windows/7z.dll
Normal file
Binary file not shown.
BIN
other/windows/7z.exe
Normal file
BIN
other/windows/7z.exe
Normal file
Binary file not shown.
Binary file not shown.
@@ -1,56 +1,22 @@
|
|||||||
****** ***** ****** UnRAR - free utility for RAR archives
|
|
||||||
** ** ** ** ** ** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
****** ******* ****** License for use and distribution of
|
|
||||||
** ** ** ** ** ** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
** ** ** ** ** ** FREEWARE version
|
|
||||||
~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
The UnRAR utility is freeware. This means:
|
|
||||||
|
|
||||||
1. All copyrights to RAR and the utility UnRAR are exclusively
|
|
||||||
owned by the author - Alexander Roshal.
|
|
||||||
|
|
||||||
2. The UnRAR utility may be freely distributed. It is allowed
|
|
||||||
to distribute UnRAR inside of other software packages.
|
|
||||||
|
|
||||||
3. THE RAR ARCHIVER AND THE UnRAR UTILITY ARE DISTRIBUTED "AS IS".
|
|
||||||
NO WARRANTY OF ANY KIND IS EXPRESSED OR IMPLIED. YOU USE AT
|
|
||||||
YOUR OWN RISK. THE AUTHOR WILL NOT BE LIABLE FOR DATA LOSS,
|
|
||||||
DAMAGES, LOSS OF PROFITS OR ANY OTHER KIND OF LOSS WHILE USING
|
|
||||||
OR MISUSING THIS SOFTWARE.
|
|
||||||
|
|
||||||
4. Neither RAR binary code, WinRAR binary code, UnRAR source or UnRAR
|
|
||||||
binary code may be used or reverse engineered to re-create the RAR
|
|
||||||
compression algorithm, which is proprietary, without written
|
|
||||||
permission of the author.
|
|
||||||
|
|
||||||
5. If you don't agree with terms of the license you must remove
|
|
||||||
UnRAR files from your storage devices and cease to use the
|
|
||||||
utility.
|
|
||||||
|
|
||||||
Thank you for your interest in RAR and UnRAR.
|
|
||||||
|
|
||||||
|
|
||||||
Alexander L. Roshal
|
|
||||||
|
|
||||||
7-Zip
|
7-Zip
|
||||||
~~~~~
|
~~~~~
|
||||||
License for use and distribution
|
License for use and distribution
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
7-Zip Copyright (C) 1999-2012 Igor Pavlov.
|
7-Zip Copyright (C) 1999-2018 Igor Pavlov.
|
||||||
|
|
||||||
Licenses for files are:
|
The licenses for files are:
|
||||||
|
|
||||||
1) 7z.dll: GNU LGPL + unRAR restriction
|
1) 7z.dll:
|
||||||
2) All other files: GNU LGPL
|
- 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".
|
||||||
|
|
||||||
The GNU LGPL + unRAR restriction means that you must follow both
|
Redistributions in binary form must reproduce related license information from this file.
|
||||||
GNU LGPL rules and unRAR restriction rules.
|
|
||||||
|
|
||||||
|
Note:
|
||||||
Note:
|
You can use 7-Zip on any computer, including a computer in a commercial
|
||||||
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.
|
organization. You don't need to register or pay for 7-Zip.
|
||||||
|
|
||||||
|
|
||||||
@@ -67,21 +33,54 @@
|
|||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You can receive a copy of the GNU Lesser General Public License from
|
You can receive a copy of the GNU Lesser General Public License from
|
||||||
http://www.gnu.org/
|
http://www.gnu.org/
|
||||||
|
|
||||||
|
|
||||||
unRAR restriction
|
|
||||||
-----------------
|
|
||||||
|
|
||||||
The decompression engine for RAR archives was developed using source
|
|
||||||
|
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.
|
code of unRAR program.
|
||||||
All copyrights to original unRAR code are owned by Alexander Roshal.
|
All copyrights to original unRAR code are owned by Alexander Roshal.
|
||||||
|
|
||||||
The license for original unRAR code has the following restriction:
|
The license for original unRAR code has the following restriction:
|
||||||
|
|
||||||
The unRAR sources cannot be used to re-create the RAR compression algorithm,
|
The unRAR sources cannot be used to re-create the RAR compression algorithm,
|
||||||
which is proprietary. Distribution of modified unRAR sources in separate form
|
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
|
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
|
stated in the documentation and source comments that the code may
|
||||||
not be used to develop a RAR (WinRAR) compatible archiver.
|
not be used to develop a RAR (WinRAR) compatible archiver.
|
||||||
|
|||||||
Binary file not shown.
@@ -1,3 +0,0 @@
|
|||||||
éd¼7¶ÍÑ<>ßñ|l“z6¯n¸I_œ—Åž:£ê-ˆ!ën‚BCDÇ}fðzIe|¦ÜÖà\9KW°f½H[íY¶LYô7^Ï@mª*<2A>YmÎ_z`3©WSD{Ö"áˆa@>®;}\¥—,D›š˜Ý·Ý!yX<79>±è–<C3A8>¯~ÿ~Y_æxdÕï BøŠT
|
|
||||||
B”𢯣
|
|
||||||
uô|91u~¿Pa¸¸LDÜjh
|
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
PyQt5>=5.6.0
|
PyQt5>=5.6.0
|
||||||
Pillow>=4.0.0
|
Pillow>=5.2.0
|
||||||
psutil>=5.0.0
|
psutil>=5.0.0
|
||||||
python-slugify>=1.2.1
|
python-slugify>=1.2.1,<8.0.0
|
||||||
raven>=6.0.0
|
raven>=6.0.0
|
||||||
|
# PyQt5-tools
|
||||||
|
mozjpeg-lossless-optimization
|
||||||
48
setup.py
Executable file → Normal file
48
setup.py
Executable file → Normal file
@@ -6,7 +6,7 @@ pip/pyinstaller build script for KCC.
|
|||||||
Install as Python package:
|
Install as Python package:
|
||||||
python3 setup.py install
|
python3 setup.py install
|
||||||
|
|
||||||
Create EXE/APP/DEB:
|
Create EXE/APP:
|
||||||
python3 setup.py build_binary
|
python3 setup.py build_binary
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -17,11 +17,14 @@ 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__
|
||||||
|
|
||||||
|
|
||||||
|
# noinspection PyUnresolvedReferences
|
||||||
class BuildBinaryCommand(distutils.cmd.Command):
|
class BuildBinaryCommand(distutils.cmd.Command):
|
||||||
description = 'build binary release'
|
description = 'build binary release'
|
||||||
user_options = []
|
user_options = []
|
||||||
@@ -36,36 +39,32 @@ 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')
|
||||||
shutil.copy('other/osx/7za', 'dist/Kindle Comic Converter.app/Contents/Resources')
|
os.makedirs('dist/Kindle Comic Converter.app/Contents/Resources/Codecs')
|
||||||
shutil.copy('other/osx/unrar', 'dist/Kindle Comic Converter.app/Contents/Resources')
|
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('other/osx/Info.plist', 'dist/Kindle Comic Converter.app/Contents')
|
||||||
shutil.copy('LICENSE.txt', 'dist/Kindle Comic Converter.app/Contents/Resources')
|
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')
|
shutil.copy('other/windows/Additional-LICENSE.txt', 'dist/Kindle Comic Converter.app/Contents/Resources')
|
||||||
os.chmod('dist/Kindle Comic Converter.app/Contents/Resources/unrar', 0o777)
|
os.chmod('dist/Kindle Comic Converter.app/Contents/Resources/7z', 0o777)
|
||||||
os.chmod('dist/Kindle Comic Converter.app/Contents/Resources/7za', 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':
|
||||||
os.system('pyinstaller -y -F -i icons\comic2ebook.ico -n KCC -w --noupx kcc.py')
|
os.system('pyinstaller -y -F -i icons\\comic2ebook.ico -n KCC_' + VERSION + ' -w --noupx kcc.py')
|
||||||
|
exit(0)
|
||||||
|
elif sys.platform == 'linux':
|
||||||
|
os.system(
|
||||||
|
'pyinstaller --hidden-import=queue -y -F -i icons/comic2ebook.ico -n kcc_linux_' + VERSION + ' kcc.py')
|
||||||
exit(0)
|
exit(0)
|
||||||
else:
|
else:
|
||||||
os.system('pyinstaller -y -F kcc.py')
|
|
||||||
os.system('mkdir -p dist/usr/bin dist/usr/share/applications dist/usr/share/doc/kindlecomicconverter '
|
|
||||||
'dist/usr/share/kindlecomicconverter dist/usr/share/lintian/overrides')
|
|
||||||
os.system('mv dist/kcc dist/usr/bin')
|
|
||||||
os.system('cp icons/comic2ebook.png dist/usr/share/kindlecomicconverter')
|
|
||||||
os.system('cp LICENSE.txt dist/usr/share/doc/kindlecomicconverter/copyright')
|
|
||||||
os.system('cp other/linux/kindlecomicconverter.desktop dist/usr/share/applications')
|
|
||||||
os.system('cp other/linux/kindlecomicconverter dist/usr/share/lintian/overrides')
|
|
||||||
os.chdir('dist')
|
|
||||||
os.system('fpm -f -s dir -t deb -n kindlecomicconverter -v ' + VERSION +
|
|
||||||
' -m "Pawel Jastrzebski <pawelj@iosphe.re>" --license "ISC" '
|
|
||||||
'--description "$(printf "Comic and Manga converter for e-book '
|
|
||||||
'readers.\nThis app allows you to transform your PNG, JPG, GIF, '
|
|
||||||
'CBZ, CBR and CB7 files\ninto EPUB or MOBI format e-books.")" '
|
|
||||||
'--url "https://kcc.iosphe.re/" --deb-priority "optional" --vendor "" '
|
|
||||||
'--category "graphics" -d "unrar | unrar-free" -d "p7zip-full" -d "libc6" usr')
|
|
||||||
exit(0)
|
exit(0)
|
||||||
|
|
||||||
|
|
||||||
@@ -93,10 +92,11 @@ setuptools.setup(
|
|||||||
packages=['kindlecomicconverter'],
|
packages=['kindlecomicconverter'],
|
||||||
install_requires=[
|
install_requires=[
|
||||||
'PyQt5>=5.6.0',
|
'PyQt5>=5.6.0',
|
||||||
'Pillow>=4.0.0',
|
'Pillow>=5.2.0',
|
||||||
'psutil>=5.0.0',
|
'psutil>=5.0.0',
|
||||||
'python-slugify>=1.2.1',
|
'python-slugify>=1.2.1,<8.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