mirror of
https://github.com/ciromattia/kcc
synced 2026-04-15 13:38:46 +00:00
Compare commits
72 Commits
7z-kindleg
...
v6.2.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1131bab41f | ||
|
|
8d204668a7 | ||
|
|
99d94ceaa7 | ||
|
|
8ff401cc3a | ||
|
|
fb7d92d737 | ||
|
|
1ca8b2c11b | ||
|
|
40e0b4853b | ||
|
|
005313f978 | ||
|
|
add2ef9faa | ||
|
|
0c98acd606 | ||
|
|
fe902ec213 | ||
|
|
4e9714e6f8 | ||
|
|
1337ad7fe3 | ||
|
|
511c7c1580 | ||
|
|
16dd034af4 | ||
|
|
d22794555f | ||
|
|
ab089adbca | ||
|
|
2c770f4562 | ||
|
|
4c73006bd8 | ||
|
|
1093dbf65a | ||
|
|
df9990c692 | ||
|
|
114f4c9e57 | ||
|
|
c2c477475d | ||
|
|
a0f8d0b5cf | ||
|
|
2fc32bae58 | ||
|
|
db25a0939c | ||
|
|
1bd7506140 | ||
|
|
4fc5cc9dfb | ||
|
|
89289412a3 | ||
|
|
193297c8fc | ||
|
|
367d71e4ad | ||
|
|
cdde0f18cd | ||
|
|
9fe82a9dd4 | ||
|
|
e958edd135 | ||
|
|
6738b70487 | ||
|
|
44094bdb21 | ||
|
|
a9a2f47e30 | ||
|
|
c35dd137ea | ||
|
|
1ea008c8f3 | ||
|
|
cbc1ed5db4 | ||
|
|
6bf662bea3 | ||
|
|
cfae306731 | ||
|
|
f6475f4c61 | ||
|
|
9646518575 | ||
|
|
937dd3984a | ||
|
|
4e6f6ec8e8 | ||
|
|
4b36fdbfa2 | ||
|
|
d8141af4eb | ||
|
|
cf38c4d445 | ||
|
|
283b2da1a0 | ||
|
|
4a9f693574 | ||
|
|
9a48887edc | ||
|
|
0981ec3c6d | ||
|
|
e0e6606736 | ||
|
|
518e67c132 | ||
|
|
6c593dac1f | ||
|
|
9d065676db | ||
|
|
9520e59a29 | ||
|
|
461a7fda88 | ||
|
|
5ccbb770a6 | ||
|
|
49bf80f5d8 | ||
|
|
33cc324381 | ||
|
|
6ba5539813 | ||
|
|
f725196106 | ||
|
|
c8ff88ed0f | ||
|
|
33fed662fe | ||
|
|
bc7cd17916 | ||
|
|
c5e1e18ac2 | ||
|
|
ee31b784cb | ||
|
|
48541404ee | ||
|
|
acbebcfd40 | ||
|
|
dd6273b864 |
6
.github/workflows/package-linux.yml
vendored
6
.github/workflows/package-linux.yml
vendored
@@ -34,8 +34,8 @@ jobs:
|
||||
- name: Install python dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y libpng-dev libjpeg-dev p7zip-full p7zip-rar python3-pyqt5 python3-pip squashfs-tools libfuse2
|
||||
python -m pip install --upgrade pip setuptools wheel certifi pyinstaller PyQt6 --no-binary pyinstaller
|
||||
sudo apt-get install -y libpng-dev libjpeg-dev p7zip-full p7zip-rar python3-pip squashfs-tools libfuse2 libxcb-cursor0
|
||||
python -m pip install --upgrade pip setuptools wheel certifi pyinstaller --no-binary pyinstaller
|
||||
python -m pip install -r requirements.txt
|
||||
- name: build binary
|
||||
run: |
|
||||
@@ -64,7 +64,7 @@ jobs:
|
||||
name: AppImage
|
||||
path: './*.AppImage*'
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@v2
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
with:
|
||||
prerelease: true
|
||||
|
||||
11
.github/workflows/package-macos.yml
vendored
11
.github/workflows/package-macos.yml
vendored
@@ -23,7 +23,10 @@ on:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: macos-latest
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ macos-12, macos-14 ]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Python
|
||||
@@ -77,10 +80,10 @@ jobs:
|
||||
- name: upload build
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: mac-os-build
|
||||
name: mac-os-build-${{ runner.arch }}
|
||||
path: dist/*.dmg
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@v2
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
with:
|
||||
prerelease: true
|
||||
@@ -95,4 +98,4 @@ jobs:
|
||||
# if: ${{ always() }}
|
||||
run: |
|
||||
security delete-keychain $RUNNER_TEMP/app-signing.keychain-db
|
||||
rm ~/Library/MobileDevice/Provisioning\ Profiles/build_pp.mobileprovision
|
||||
rm ~/Library/MobileDevice/Provisioning\ Profiles/build_pp.mobileprovision
|
||||
|
||||
@@ -26,33 +26,27 @@ jobs:
|
||||
# run: |
|
||||
# pyi-makespec -F -i icons\\comic2ebook.ico -n KCC_test -w --noupx kcc.py
|
||||
- name: Package Application
|
||||
uses: JackMcKew/pyinstaller-action-windows@python3-10-pyinstaller-5-3
|
||||
with:
|
||||
path: .
|
||||
spec: ./kcc.spec
|
||||
- name: Package Application
|
||||
uses: JackMcKew/pyinstaller-action-windows@python3-10-pyinstaller-5-3
|
||||
uses: JackMcKew/pyinstaller-action-windows@main
|
||||
with:
|
||||
path: .
|
||||
spec: ./kcc-c2e.spec
|
||||
- name: Package Application
|
||||
uses: JackMcKew/pyinstaller-action-windows@python3-10-pyinstaller-5-3
|
||||
uses: JackMcKew/pyinstaller-action-windows@main
|
||||
with:
|
||||
path: .
|
||||
spec: ./kcc-c2p.spec
|
||||
- name: rename binaries
|
||||
run: |
|
||||
version_built=$(cat kindlecomicconverter/__init__.py | grep version | awk '{print $3}' | sed "s/[^.0-9b]//g")
|
||||
mv dist/windows/kcc.exe dist/windows/kcc_${version_built}.exe
|
||||
mv dist/windows/kcc-c2e.exe dist/windows/kcc_c2e_${version_built}.exe
|
||||
mv dist/windows/kcc-c2p.exe dist/windows/kcc_c2p_${version_built}.exe
|
||||
mv dist/windows/kcc-c2e.exe dist/windows/KCC_c2e_${version_built}.exe
|
||||
mv dist/windows/kcc-c2p.exe dist/windows/KCC_c2p_${version_built}.exe
|
||||
- name: upload build
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: windows-build
|
||||
path: dist/windows/*.exe
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@v2
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
with:
|
||||
prerelease: true
|
||||
|
||||
2
.github/workflows/package-windows.yml
vendored
2
.github/workflows/package-windows.yml
vendored
@@ -47,7 +47,7 @@ jobs:
|
||||
name: windows-build
|
||||
path: dist/*.exe
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@v2
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
with:
|
||||
prerelease: true
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Select final stage based on TARGETARCH ARG
|
||||
FROM ghcr.io/ciromattia/kcc:docker-base-20230514
|
||||
FROM ghcr.io/ciromattia/kcc:docker-base-20240928
|
||||
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'
|
||||
@@ -16,4 +16,4 @@ COPY . /opt/kcc
|
||||
RUN cat /opt/kcc/kindlecomicconverter/__init__.py | grep version | awk '{print $3}' | sed "s/'//g" > /IMAGE_VERSION
|
||||
|
||||
ENTRYPOINT ["/opt/kcc/kcc-c2e.py"]
|
||||
CMD ["-h"]
|
||||
CMD ["-h"]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM --platform=linux/amd64 python:3.11-slim-bullseye as compile-amd64
|
||||
FROM --platform=linux/amd64 python:3.12-slim-bullseye as compile-amd64
|
||||
ARG TARGETOS
|
||||
ARG TARGETARCH
|
||||
ARG TARGETVARIANT
|
||||
@@ -8,7 +8,7 @@ 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 && \
|
||||
apt-get install -y libpng-dev libjpeg-dev p7zip-full unrar-free libgl1 && \
|
||||
python -m pip install --upgrade pip && \
|
||||
python -m venv /opt/venv && \
|
||||
python -m pip install -r /opt/kcc/requirements.txt
|
||||
@@ -16,7 +16,7 @@ RUN DEBIAN_FRONTEND=noninteractive apt-get update -y && apt-get -yq upgrade && \
|
||||
|
||||
######################################################################################
|
||||
|
||||
FROM --platform=linux/arm64 python:3.11-slim-bullseye as compile-arm64
|
||||
FROM --platform=linux/arm64 python:3.12-slim-bullseye as compile-arm64
|
||||
ARG TARGETOS
|
||||
ARG TARGETARCH
|
||||
ARG TARGETVARIANT
|
||||
@@ -28,6 +28,9 @@ ENV LC_ALL=C.UTF-8 \
|
||||
|
||||
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
|
||||
|
||||
COPY requirements.txt /opt/kcc/
|
||||
ENV PATH="/opt/venv/bin:$PATH"
|
||||
|
||||
RUN set -x && \
|
||||
TEMP_PACKAGES=() && \
|
||||
KEPT_PACKAGES=() && \
|
||||
@@ -55,7 +58,6 @@ RUN set -x && \
|
||||
KEPT_PACKAGES+=(p7zip-full) && \
|
||||
KEPT_PACKAGES+=(python3) && \
|
||||
KEPT_PACKAGES+=(python3-pip) && \
|
||||
KEPT_PACKAGES+=(python3-pyqt5) && \
|
||||
KEPT_PACKAGES+=(unrar-free) && \
|
||||
# Install packages
|
||||
DEBIAN_FRONTEND=noninteractive apt-get update -y && apt-get -yq upgrade && \
|
||||
@@ -65,14 +67,13 @@ RUN set -x && \
|
||||
&& \
|
||||
# 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
|
||||
python -m pip install -r /opt/kcc/requirements.txt
|
||||
|
||||
|
||||
######################################################################################
|
||||
|
||||
FROM --platform=linux/arm/v7 python:3.11-slim-bullseye as compile-armv7
|
||||
FROM --platform=linux/arm/v7 python:3.12-slim-bullseye as compile-armv7
|
||||
ARG TARGETOS
|
||||
ARG TARGETARCH
|
||||
ARG TARGETVARIANT
|
||||
@@ -84,6 +85,9 @@ ENV LC_ALL=C.UTF-8 \
|
||||
|
||||
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
|
||||
|
||||
COPY requirements.txt /opt/kcc/
|
||||
ENV PATH="/opt/venv/bin:$PATH"
|
||||
|
||||
RUN set -x && \
|
||||
TEMP_PACKAGES=() && \
|
||||
KEPT_PACKAGES=() && \
|
||||
@@ -112,7 +116,6 @@ RUN set -x && \
|
||||
KEPT_PACKAGES+=(p7zip-full) && \
|
||||
KEPT_PACKAGES+=(python3) && \
|
||||
KEPT_PACKAGES+=(python3-pip) && \
|
||||
KEPT_PACKAGES+=(python3-pyqt5) && \
|
||||
KEPT_PACKAGES+=(unrar-free) && \
|
||||
# Install packages
|
||||
DEBIAN_FRONTEND=noninteractive apt-get update -y && apt-get -yq upgrade && \
|
||||
@@ -122,19 +125,18 @@ RUN set -x && \
|
||||
&& \
|
||||
# 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
|
||||
python -m pip install --upgrade pillow psutil requests python-slugify raven packaging mozjpeg-lossless-optimization natsort distro
|
||||
|
||||
|
||||
######################################################################################
|
||||
FROM --platform=linux/amd64 python:3.11-slim-bullseye as build-amd64
|
||||
FROM --platform=linux/amd64 python:3.12-slim-bullseye as build-amd64
|
||||
COPY --from=compile-amd64 /opt/venv /opt/venv
|
||||
|
||||
FROM --platform=linux/arm64 python:3.11-slim-bullseye as build-arm64
|
||||
FROM --platform=linux/arm64 python:3.12-slim-bullseye as build-arm64
|
||||
COPY --from=compile-arm64 /opt/venv /opt/venv
|
||||
|
||||
FROM --platform=linux/arm/v7 python:3.11-slim-bullseye as build-armv7
|
||||
FROM --platform=linux/arm/v7 python:3.12-slim-bullseye as build-armv7
|
||||
COPY --from=compile-armv7 /opt/venv /opt/venv
|
||||
######################################################################################
|
||||
|
||||
@@ -158,5 +160,5 @@ WORKDIR /app
|
||||
RUN DEBIAN_FRONTEND=noninteractive apt-get update -y && apt-get -yq upgrade && \
|
||||
apt-get install -y p7zip-full unrar-free && \
|
||||
ln -s /app/kindlegen /bin/kindlegen && \
|
||||
echo docker-base-20230514 > /IMAGE_VERSION
|
||||
echo docker-base-20240928 > /IMAGE_VERSION
|
||||
|
||||
|
||||
115
README.md
115
README.md
@@ -2,8 +2,8 @@
|
||||
|
||||
|
||||
|
||||
[](https://github.com/ciromattia/kcc/releases)
|
||||
[](https://github.com/ciromattia/kcc/pkgs/container/kcc)
|
||||
[](https://github.com/ciromattia/kcc/releases)
|
||||
[](https://github.com/ciromattia/kcc/pkgs/container/kcc)
|
||||
|
||||
|
||||
**Kindle Comic Converter** is a Python app to convert comic/manga files or folders to EPUB, Panel View MOBI or E-Ink optimized CBZ.
|
||||
@@ -22,13 +22,13 @@ If you have some **technical** problems using KCC please [file an issue here](ht
|
||||
If you can fix an open issue, fork & make a pull request.
|
||||
|
||||
If you find **KCC** valuable you can consider donating to the authors:
|
||||
- Ciro Mattia Gonano:
|
||||
- Ciro Mattia Gonano (founder, active 2013-2014):
|
||||
- [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=D8WNYNPBGDAS2)
|
||||
- [](http://flattr.com/thing/2260449/ciromattiakcc-on-GitHub)
|
||||
- Paweł Jastrzębski:
|
||||
- Paweł Jastrzębski (active 2013-2019):
|
||||
- [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=YTTJ4LK2JDHPS)
|
||||
- [](https://jastrzeb.ski/donate/)
|
||||
- Alex Xu
|
||||
- Alex Xu (active 2023-Present)
|
||||
- [](https://www.paypal.com/donate/?business=QFJVE7A6LCP6U&no_recurring=0&item_name=Kindle+Comic+Converter¤cy_code=USD)
|
||||
|
||||
|
||||
@@ -36,11 +36,12 @@ If you find **KCC** valuable you can consider donating to the authors:
|
||||
|
||||
- **https://github.com/ciromattia/kcc/releases**
|
||||
|
||||
Click on **Assets** of the latest release.
|
||||
Click on **Assets** of the latest release.
|
||||
|
||||
You probably want either
|
||||
- `kcc_*.*.*.exe` (Windows)
|
||||
- `KindleComicConverter_osx_*.*.*.dmg` (Mac)
|
||||
You probably want either
|
||||
- `KCC_*.*.*.exe` (Windows)
|
||||
- `kcc_macos_arm_*.*.*.dmg` (recent Mac with Apple Silicon M1 chip or later)
|
||||
- `kcc_macos_i386_*.*.*.dmg` (older Mac with Intel chip)
|
||||
|
||||
The `c2e` and `c2p` versions are command line tools for power users.
|
||||
|
||||
@@ -50,33 +51,28 @@ On Mac, right click open to get past the security warning.
|
||||
|
||||
For flatpak, Docker, and AppImage versions, refer to the wiki: https://github.com/ciromattia/kcc/wiki/Installation
|
||||
|
||||
## FAQ
|
||||
|
||||
- [Kindle Scribe cover guide](https://github.com/ciromattia/kcc/issues/508) (also works for older Kindles)
|
||||
- [Windows 7 support](https://github.com/ciromattia/kcc/issues/678)
|
||||
- [Combine files/chapters](https://github.com/ciromattia/kcc/issues/612#issuecomment-2117985011)
|
||||
- [Flatpak mobi conversion stuck](https://github.com/ciromattia/kcc/wiki/Installation#linux)
|
||||
|
||||
## PREREQUISITES
|
||||
|
||||
You'll need to install various tools to access important but optional features.
|
||||
|
||||
The installation process has been greatly streamlined. No need to add 7z to PATH or locate KindleGen from the internet and put it in a special folder with KCC. Just run it and KCC will tell you what to install.
|
||||
|
||||
### 7-Zip
|
||||
|
||||
#### Windows 7-Zip
|
||||
|
||||
First install 7z from https://www.7-zip.org/ or with command line:
|
||||
```
|
||||
winget install --id 7zip.7zip
|
||||
```
|
||||
|
||||
#### macOS 7-Zip/Unar
|
||||
with [Homebrew](https://brew.sh/) installed
|
||||
```
|
||||
brew install p7zip
|
||||
brew install unar
|
||||
```
|
||||
You'll need to install various tools to access important but optional features. Close and re-open KCC to get KCC to detect them.
|
||||
|
||||
### KindleGen
|
||||
|
||||
#### Windows / macOS KindleGen
|
||||
On Windows and macOS, install [Kindle Previewer](https://www.amazon.com/Kindle-Previewer/b?ie=UTF8&node=21381691011) and `kindlegen` will be autodetected from it.
|
||||
|
||||
Install [Kindle Previewer 3 (KP3)](https://www.amazon.com/Kindle-Previewer/b?ie=UTF8&node=21381691011). KCC will automatically detect KindleGen from it.
|
||||
If you have issues detecting it, get stuck on the MOBI conversion step, or use Linux AppImage or Flatpak, refer to the wiki: https://github.com/ciromattia/kcc/wiki/Installation#kindlegen
|
||||
|
||||
### 7-Zip
|
||||
|
||||
This is no longer required as of KCC 6.1.
|
||||
|
||||
If you still need it, refer to the wiki: https://github.com/ciromattia/kcc/wiki/Installation#7-zip
|
||||
|
||||
## INPUT FORMATS
|
||||
**KCC** can understand and convert, at the moment, the following input types:
|
||||
@@ -103,7 +99,7 @@ sudo apt-get install python3 p7zip-full python3-pil python3-psutil python3-slugi
|
||||
|
||||
```
|
||||
'K1': ("Kindle 1", (600, 670), Palette4, 1.8),
|
||||
'K11': ("Kindle 11", (1072, 1448), Palette16, 1.8),
|
||||
'K11': ("Kindle 11/12", (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),
|
||||
@@ -111,6 +107,8 @@ sudo apt-get install python3 p7zip-full python3-pil python3-psutil python3-slugi
|
||||
'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),
|
||||
'KPW6': ("Kindle Paperwhite 6", (1264, 1680), Palette16, 1.8),
|
||||
'KCS12': ("Kindle Colorsoft", (1264, 1680), 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),
|
||||
@@ -122,14 +120,15 @@ sudo apt-get install python3 p7zip-full python3-pil python3-psutil python3-slugi
|
||||
'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),
|
||||
'KoCC': ("Kobo Clara Colour", (1072, 1448), Palette16, 1.8),
|
||||
'KoL': ("Kobo Libra H2O/Kobo Libra 2", (1264, 1680), Palette16, 1.8),
|
||||
'KoLC': ("Kobo Libra Colour", (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:
|
||||
|
||||
```
|
||||
@@ -210,8 +209,56 @@ OTHER:
|
||||
-h, --help Show this help message and exit
|
||||
```
|
||||
|
||||
## INSTALL FROM SOURCE
|
||||
|
||||
This section is for developers who want to contribute to KCC or power users who want to run the latest code without waiting for an official release.
|
||||
|
||||
Easiest to use [GitHub Desktop](https://desktop.github.com) to clone the KCC repo. From GitHub Desktop, click on `Repository` in the toolbar, then `Command Prompt` (Windows)/`Terminal` (Mac) to open a window in the KCC repo.
|
||||
|
||||
Depending on your system [Python](https://www.python.org) may be called either `python` or `python3`. We use virtual environments (venv) to manage dependencies.
|
||||
|
||||
If you want to edit the code, a good code editor is [VS Code](https://code.visualstudio.com).
|
||||
|
||||
If you want to edit the `.ui` files, use [Qt Creator](https://www.qt.io/download-qt-installer-oss), included in **Qt for desktop development**.
|
||||
Then use the `gen_ui_files` scripts to autogenerate the python UI.
|
||||
|
||||
|
||||
### Windows install from source
|
||||
|
||||
One time setup and running for the first time:
|
||||
```
|
||||
python -m venv venv
|
||||
venv\Scripts\activate.bat
|
||||
pip install -r requirements.txt
|
||||
python kcc.py
|
||||
```
|
||||
|
||||
Every time you close Command Prompt, you will need to re-activate the virtual environment and re-run:
|
||||
|
||||
```
|
||||
venv\Scripts\activate.bat
|
||||
python kcc.py
|
||||
```
|
||||
|
||||
### macOS install from source
|
||||
|
||||
One time setup and running for the first time:
|
||||
```
|
||||
python3 -m venv venv
|
||||
source venv/bin/activate
|
||||
pip install -r requirements.txt
|
||||
python kcc.py
|
||||
```
|
||||
|
||||
Every time you close Terminal, you will need to reactivate the virtual environment and re-run:
|
||||
|
||||
```
|
||||
source venv/bin/activate
|
||||
python kcc.py
|
||||
```
|
||||
|
||||
## CREDITS
|
||||
**KCC** is made by
|
||||
**KCC** is made by
|
||||
|
||||
- [Ciro Mattia Gonano](http://github.com/ciromattia)
|
||||
- [Paweł Jastrzębski](http://github.com/AcidWeb)
|
||||
@@ -246,5 +293,5 @@ The app relies and includes the following scripts:
|
||||
Please check [wiki page](https://github.com/ciromattia/kcc/wiki/Known-issues).
|
||||
|
||||
## COPYRIGHT
|
||||
Copyright (c) 2012-2023 Ciro Mattia Gonano, Paweł Jastrzębski and Darodi.
|
||||
Copyright (c) 2012-2023 Ciro Mattia Gonano, Paweł Jastrzębski and Darodi.
|
||||
**KCC** is released under ISC LICENSE; see [LICENSE.txt](./LICENSE.txt) for further details.
|
||||
|
||||
@@ -5,7 +5,7 @@ channels:
|
||||
dependencies:
|
||||
- python=3.11
|
||||
- Pillow>=5.2.0
|
||||
- psutil>=5.0.0
|
||||
- psutil>=5.9.5
|
||||
- python-slugify>=1.2.1
|
||||
- raven>=6.0.0
|
||||
- distro
|
||||
@@ -13,4 +13,4 @@ dependencies:
|
||||
- pip
|
||||
- pip:
|
||||
- mozjpeg-lossless-optimization>=1.1.2
|
||||
- PyQt5>=5.6.0
|
||||
- pyside6>=6.5.1
|
||||
|
||||
@@ -1,11 +1,3 @@
|
||||
|
||||
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
|
||||
pyside6-uic gui/KCC.ui > kindlecomicconverter/KCC_ui.py
|
||||
pyside6-uic gui/MetaEditor.ui > kindlecomicconverter/KCC_ui_editor.py
|
||||
pyside6-rcc gui/KCC.qrc > kindlecomicconverter/KCC_rc.py
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
#!/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
|
||||
pyside6-uic gui/KCC.ui --from-imports > kindlecomicconverter/KCC_ui.py
|
||||
pyside6-uic gui/MetaEditor.ui --from-imports > kindlecomicconverter/KCC_ui_editor.py
|
||||
pyside6-rcc gui/KCC.qrc > kindlecomicconverter/KCC_rc.py
|
||||
|
||||
142
gui/KCC.ui
142
gui/KCC.ui
@@ -37,59 +37,36 @@
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="1" column="1">
|
||||
<widget class="QCheckBox" name="upscaleBox">
|
||||
<item row="0" column="2">
|
||||
<widget class="QCheckBox" name="qualityBox">
|
||||
<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'><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 name="text">
|
||||
<string>Stretch/Upscale</string>
|
||||
<string>Panel View 4/2/HQ</string>
|
||||
</property>
|
||||
<property name="tristate">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QCheckBox" name="rotateBox">
|
||||
<item row="4" column="1">
|
||||
<widget class="QCheckBox" name="deleteBox">
|
||||
<property name="toolTip">
|
||||
<string><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></string>
|
||||
<string>Delete input file(s) or directory. It's not recoverable!</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Spread splitter</string>
|
||||
</property>
|
||||
<property name="tristate">
|
||||
<bool>true</bool>
|
||||
<string>Delete input</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QCheckBox" name="outputSplit">
|
||||
<item row="3" column="1">
|
||||
<widget class="QCheckBox" name="maximizeStrips">
|
||||
<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><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>Output split</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="webtoonBox">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p style='white-space:pre'>Enable special parsing mode for Korean Webtoons.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Webtoon mode</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QCheckBox" name="colorBox">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p style='white-space:pre'>Disable conversion to grayscale.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Color mode</string>
|
||||
<string>1x4 to 2x2 strips</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -116,6 +93,29 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="webtoonBox">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p style='white-space:pre'>Enable special parsing mode for Korean Webtoons.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Webtoon mode</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QCheckBox" name="upscaleBox">
|
||||
<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>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Stretch/Upscale</string>
|
||||
</property>
|
||||
<property name="tristate">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="mangaBox">
|
||||
<property name="toolTip">
|
||||
@@ -126,42 +126,19 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QCheckBox" name="qualityBox">
|
||||
<item row="0" column="1">
|
||||
<widget class="QCheckBox" name="rotateBox">
|
||||
<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><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></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Panel View 4/2/HQ</string>
|
||||
<string>Spread splitter</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">
|
||||
@@ -175,13 +152,36 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QCheckBox" name="deleteBox">
|
||||
<item row="2" column="1">
|
||||
<widget class="QCheckBox" name="outputSplit">
|
||||
<property name="toolTip">
|
||||
<string>Delete input file(s) or directory. It's not recoverable!</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 name="text">
|
||||
<string>Delete input</string>
|
||||
<string>Output split</string>
|
||||
</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="2" column="2">
|
||||
<widget class="QCheckBox" name="colorBox">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p style='white-space:pre'>Disable conversion to grayscale.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Color mode</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -195,6 +195,16 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QCheckBox" name="dedupeCoverBox">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Don't duplicate the first page as the cover. Useful for 2 page spread alignment.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>De-dupe cover</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -8,7 +8,7 @@ a = Analysis(['kcc-c2e.py'],
|
||||
pathex=['.'],
|
||||
binaries=[],
|
||||
datas=[],
|
||||
hiddenimports=[],
|
||||
hiddenimports=['_cffi_backend'],
|
||||
hookspath=[],
|
||||
runtime_hooks=[],
|
||||
excludes=[],
|
||||
|
||||
@@ -8,7 +8,7 @@ a = Analysis(['kcc-c2p.py'],
|
||||
pathex=['.'],
|
||||
binaries=[],
|
||||
datas=[],
|
||||
hiddenimports=[],
|
||||
hiddenimports=['_cffi_backend'],
|
||||
hookspath=[],
|
||||
runtime_hooks=[],
|
||||
excludes=[],
|
||||
|
||||
6
kcc.py
6
kcc.py
@@ -50,7 +50,13 @@ elif sys.platform.startswith('win'):
|
||||
win_paths = [
|
||||
os.path.expandvars('%LOCALAPPDATA%\\Amazon\\KC2'),
|
||||
os.path.expandvars('%LOCALAPPDATA%\\Amazon\\Kindle Previewer 3\\lib\\fc\\bin\\'),
|
||||
os.path.expandvars('%UserProfile%\\Kindle Previewer 3\\lib\\fc\\bin\\'),
|
||||
'C:\\Apps\\Kindle Previewer 3\\lib\\fc\\bin',
|
||||
'D:\\Apps\\Kindle Previewer 3\\lib\\fc\\bin',
|
||||
'E:\\Apps\\Kindle Previewer 3\\lib\\fc\\bin',
|
||||
'C:\\Program Files\\7-Zip',
|
||||
'D:\\Program Files\\7-Zip',
|
||||
'E:\\Program Files\\7-Zip',
|
||||
]
|
||||
if getattr(sys, 'frozen', False):
|
||||
os.environ['PATH'] += os.pathsep + os.pathsep.join(win_paths)
|
||||
|
||||
39
kcc.spec
39
kcc.spec
@@ -1,39 +0,0 @@
|
||||
# -*- mode: python ; coding: utf-8 -*-
|
||||
|
||||
|
||||
block_cipher = None
|
||||
|
||||
|
||||
a = Analysis(['kcc.py'],
|
||||
pathex=['.'],
|
||||
binaries=[],
|
||||
datas=[],
|
||||
hiddenimports=[],
|
||||
hookspath=[],
|
||||
runtime_hooks=[],
|
||||
excludes=[],
|
||||
win_no_prefer_redirects=False,
|
||||
win_private_assemblies=False,
|
||||
cipher=block_cipher,
|
||||
noarchive=False)
|
||||
pyz = PYZ(a.pure, a.zipped_data,
|
||||
cipher=block_cipher)
|
||||
|
||||
exe = EXE(pyz,
|
||||
a.scripts,
|
||||
a.binaries,
|
||||
a.zipfiles,
|
||||
a.datas,
|
||||
[],
|
||||
name='kcc',
|
||||
debug=False,
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
upx=False,
|
||||
upx_exclude=[],
|
||||
runtime_tmpdir=None,
|
||||
console=False,
|
||||
disable_windowed_traceback=False,
|
||||
target_arch=None,
|
||||
codesign_identity=None,
|
||||
entitlements_file=None , icon='icons\\comic2ebook.ico')
|
||||
@@ -18,7 +18,6 @@
|
||||
# PERFORMANCE OF THIS SOFTWARE.
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
from urllib.parse import unquote
|
||||
from time import sleep
|
||||
@@ -27,14 +26,16 @@ from subprocess import STDOUT, PIPE
|
||||
|
||||
import requests
|
||||
# noinspection PyUnresolvedReferences
|
||||
from PyQt5 import QtGui, QtCore, QtWidgets, QtNetwork
|
||||
from PySide6 import QtGui, QtCore, QtWidgets, QtNetwork
|
||||
from PySide6.QtCore import Qt
|
||||
from xml.sax.saxutils import escape
|
||||
from psutil import Process
|
||||
from copy import copy
|
||||
from distutils.version import StrictVersion
|
||||
from packaging.version import Version
|
||||
from raven import Client
|
||||
from tempfile import gettempdir
|
||||
from .shared import md5Checksum, HTMLStripper, sanitizeTrace, walkLevel, subprocess_run_silent
|
||||
|
||||
from .shared import HTMLStripper, sanitizeTrace, walkLevel, subprocess_run
|
||||
from . import __version__
|
||||
from . import comic2ebook
|
||||
from . import metadata
|
||||
@@ -44,7 +45,7 @@ from . import KCC_ui_editor
|
||||
|
||||
|
||||
class QApplicationMessaging(QtWidgets.QApplication):
|
||||
messageFromOtherInstance = QtCore.pyqtSignal(bytes)
|
||||
messageFromOtherInstance = QtCore.Signal(bytes)
|
||||
|
||||
def __init__(self, argv):
|
||||
QtWidgets.QApplication.__init__(self, argv)
|
||||
@@ -52,7 +53,7 @@ class QApplicationMessaging(QtWidgets.QApplication):
|
||||
self._timeout = 1000
|
||||
self._locked = False
|
||||
socket = QtNetwork.QLocalSocket(self)
|
||||
socket.connectToServer(self._key, QtCore.QIODevice.WriteOnly)
|
||||
socket.connectToServer(self._key, QtCore.QIODeviceBase.OpenModeFlag.WriteOnly)
|
||||
if not socket.waitForConnected(self._timeout):
|
||||
self._server = QtNetwork.QLocalServer(self)
|
||||
self._server.newConnection.connect(self.handleMessage)
|
||||
@@ -66,7 +67,7 @@ class QApplicationMessaging(QtWidgets.QApplication):
|
||||
self._server.close()
|
||||
|
||||
def event(self, e):
|
||||
if e.type() == QtCore.QEvent.FileOpen:
|
||||
if e.type() == QtCore.QEvent.Type.FileOpen:
|
||||
self.messageFromOtherInstance.emit(bytes(e.file(), 'UTF-8'))
|
||||
return True
|
||||
else:
|
||||
@@ -82,7 +83,7 @@ class QApplicationMessaging(QtWidgets.QApplication):
|
||||
|
||||
def sendMessage(self, message):
|
||||
socket = QtNetwork.QLocalSocket(self)
|
||||
socket.connectToServer(self._key, QtCore.QIODevice.WriteOnly)
|
||||
socket.connectToServer(self._key, QtCore.QIODeviceBase.OpenModeFlag.WriteOnly)
|
||||
socket.waitForConnected(self._timeout)
|
||||
socket.write(bytes(message, 'UTF-8'))
|
||||
socket.waitForBytesWritten(self._timeout)
|
||||
@@ -90,40 +91,40 @@ class QApplicationMessaging(QtWidgets.QApplication):
|
||||
|
||||
|
||||
class QMainWindowKCC(QtWidgets.QMainWindow):
|
||||
progressBarTick = QtCore.pyqtSignal(str)
|
||||
modeConvert = QtCore.pyqtSignal(int)
|
||||
addMessage = QtCore.pyqtSignal(str, str, bool)
|
||||
addTrayMessage = QtCore.pyqtSignal(str, str)
|
||||
showDialog = QtCore.pyqtSignal(str, str)
|
||||
hideProgressBar = QtCore.pyqtSignal()
|
||||
forceShutdown = QtCore.pyqtSignal()
|
||||
progressBarTick = QtCore.Signal(str)
|
||||
modeConvert = QtCore.Signal(int)
|
||||
addMessage = QtCore.Signal(str, str, bool)
|
||||
addTrayMessage = QtCore.Signal(str, str)
|
||||
showDialog = QtCore.Signal(str, str)
|
||||
hideProgressBar = QtCore.Signal()
|
||||
forceShutdown = QtCore.Signal()
|
||||
|
||||
|
||||
class Icons:
|
||||
def __init__(self):
|
||||
self.deviceKindle = QtGui.QIcon()
|
||||
self.deviceKindle.addPixmap(QtGui.QPixmap(":/Devices/icons/Kindle.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||
self.deviceKindle.addPixmap(QtGui.QPixmap(":/Devices/icons/Kindle.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
|
||||
self.deviceKobo = QtGui.QIcon()
|
||||
self.deviceKobo.addPixmap(QtGui.QPixmap(":/Devices/icons/Kobo.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||
self.deviceKobo.addPixmap(QtGui.QPixmap(":/Devices/icons/Kobo.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
|
||||
self.deviceOther = QtGui.QIcon()
|
||||
self.deviceOther.addPixmap(QtGui.QPixmap(":/Devices/icons/Other.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||
self.deviceOther.addPixmap(QtGui.QPixmap(":/Devices/icons/Other.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
|
||||
|
||||
self.MOBIFormat = QtGui.QIcon()
|
||||
self.MOBIFormat.addPixmap(QtGui.QPixmap(":/Formats/icons/MOBI.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||
self.MOBIFormat.addPixmap(QtGui.QPixmap(":/Formats/icons/MOBI.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
|
||||
self.CBZFormat = QtGui.QIcon()
|
||||
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.Mode.Normal, QtGui.QIcon.State.Off)
|
||||
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.Mode.Normal, QtGui.QIcon.State.Off)
|
||||
|
||||
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.Mode.Normal, QtGui.QIcon.State.Off)
|
||||
self.warning = QtGui.QIcon()
|
||||
self.warning.addPixmap(QtGui.QPixmap(":/Status/icons/warning.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||
self.warning.addPixmap(QtGui.QPixmap(":/Status/icons/warning.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
|
||||
self.error = QtGui.QIcon()
|
||||
self.error.addPixmap(QtGui.QPixmap(":/Status/icons/error.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||
self.error.addPixmap(QtGui.QPixmap(":/Status/icons/error.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
|
||||
|
||||
self.programIcon = QtGui.QIcon()
|
||||
self.programIcon.addPixmap(QtGui.QPixmap(":/Icon/icons/comic2ebook.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||
self.programIcon.addPixmap(QtGui.QPixmap(":/Icon/icons/comic2ebook.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
|
||||
|
||||
|
||||
class VersionThread(QtCore.QThread):
|
||||
@@ -145,9 +146,9 @@ class VersionThread(QtCore.QThread):
|
||||
latest_version = json_parser["tag_name"]
|
||||
latest_version = re.sub(r'^v', "", latest_version)
|
||||
|
||||
if ("b" not in __version__ and StrictVersion(latest_version) > StrictVersion(__version__)) \
|
||||
if ("b" not in __version__ and Version(latest_version) > Version(__version__)) \
|
||||
or ("b" in __version__
|
||||
and StrictVersion(latest_version) >= StrictVersion(re.sub(r'b.*', '', __version__))):
|
||||
and Version(latest_version) >= Version(re.sub(r'b.*', '', __version__))):
|
||||
MW.addMessage.emit('<a href="' + html_url + '"><b>The new version is available!</b></a>', 'warning',
|
||||
False)
|
||||
except Exception:
|
||||
@@ -220,28 +221,28 @@ class WorkerThread(QtCore.QThread):
|
||||
options.format = gui_current_format
|
||||
if GUI.mangaBox.isChecked():
|
||||
options.righttoleft = True
|
||||
if GUI.rotateBox.checkState() == 1:
|
||||
if GUI.rotateBox.checkState() == Qt.CheckState.PartiallyChecked:
|
||||
options.splitter = 2
|
||||
elif GUI.rotateBox.checkState() == 2:
|
||||
elif GUI.rotateBox.checkState() == Qt.CheckState.Checked:
|
||||
options.splitter = 1
|
||||
if GUI.qualityBox.checkState() == 1:
|
||||
if GUI.qualityBox.checkState() == Qt.CheckState.PartiallyChecked:
|
||||
options.autoscale = True
|
||||
elif GUI.qualityBox.checkState() == 2:
|
||||
elif GUI.qualityBox.checkState() == Qt.CheckState.Checked:
|
||||
options.hq = True
|
||||
if GUI.webtoonBox.isChecked():
|
||||
options.webtoon = True
|
||||
if GUI.upscaleBox.checkState() == 1:
|
||||
if GUI.upscaleBox.checkState() == Qt.CheckState.PartiallyChecked:
|
||||
options.stretch = True
|
||||
elif GUI.upscaleBox.checkState() == 2:
|
||||
elif GUI.upscaleBox.checkState() == Qt.CheckState.Checked:
|
||||
options.upscale = True
|
||||
if GUI.gammaBox.isChecked() and float(GUI.gammaValue) > 0.09:
|
||||
options.gamma = float(GUI.gammaValue)
|
||||
options.cropping = GUI.croppingBox.checkState()
|
||||
if GUI.croppingBox.checkState() >= 1:
|
||||
options.cropping = GUI.croppingBox.checkState().value
|
||||
if GUI.croppingBox.checkState() != Qt.CheckState.Unchecked:
|
||||
options.croppingp = float(GUI.croppingPowerValue)
|
||||
if GUI.borderBox.checkState() == 1:
|
||||
if GUI.borderBox.checkState() == Qt.CheckState.PartiallyChecked:
|
||||
options.white_borders = True
|
||||
elif GUI.borderBox.checkState() == 2:
|
||||
elif GUI.borderBox.checkState() == Qt.CheckState.Checked:
|
||||
options.black_borders = True
|
||||
if GUI.outputSplit.isChecked():
|
||||
options.batchsplit = 2
|
||||
@@ -253,13 +254,17 @@ class WorkerThread(QtCore.QThread):
|
||||
options.noprocessing = True
|
||||
if GUI.deleteBox.isChecked():
|
||||
options.delete = True
|
||||
if GUI.mozJpegBox.checkState() == 1:
|
||||
if GUI.dedupeCoverBox.isChecked():
|
||||
options.dedupecover = True
|
||||
if GUI.mozJpegBox.checkState() == Qt.CheckState.PartiallyChecked:
|
||||
options.forcepng = True
|
||||
elif GUI.mozJpegBox.checkState() == 2:
|
||||
elif GUI.mozJpegBox.checkState() == Qt.CheckState.Checked:
|
||||
options.mozjpeg = True
|
||||
if GUI.currentMode > 2:
|
||||
options.customwidth = str(GUI.widthBox.value())
|
||||
options.customheight = str(GUI.heightBox.value())
|
||||
if GUI.targetDirectory != '':
|
||||
options.output = GUI.targetDirectory
|
||||
|
||||
for i in range(GUI.jobList.count()):
|
||||
# Make sure that we don't consider any system message as job to do
|
||||
@@ -428,7 +433,7 @@ class SystemTrayIcon(QtWidgets.QSystemTrayIcon):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
if self.isSystemTrayAvailable():
|
||||
QtWidgets.QSystemTrayIcon.__init__(self, GUI.icons.programIcon, MW)
|
||||
self.setIcon(GUI.icons.programIcon)
|
||||
self.activated.connect(self.catchClicks)
|
||||
|
||||
def catchClicks(self):
|
||||
@@ -437,7 +442,7 @@ class SystemTrayIcon(QtWidgets.QSystemTrayIcon):
|
||||
MW.activateWindow()
|
||||
|
||||
def addTrayMessage(self, message, icon):
|
||||
icon = eval('QtWidgets.QSystemTrayIcon.' + icon)
|
||||
icon = getattr(QtWidgets.QSystemTrayIcon.MessageIcon, icon)
|
||||
if self.supportsMessages() and not MW.isActiveWindow():
|
||||
self.showMessage('Kindle Comic Converter', message, icon)
|
||||
|
||||
@@ -459,7 +464,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
||||
if self.needClean:
|
||||
self.needClean = False
|
||||
GUI.jobList.clear()
|
||||
if self.sevenzip:
|
||||
if self.tar or self.sevenzip:
|
||||
fnames = QtWidgets.QFileDialog.getOpenFileNames(MW, 'Select file', self.lastPath,
|
||||
'Comic (*.cbz *.cbr *.cb7 *.zip *.rar *.7z *.pdf);;All (*.*)')
|
||||
else:
|
||||
@@ -489,6 +494,8 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
||||
else:
|
||||
fname = ['']
|
||||
self.showDialog("Editor is disabled due to a lack of 7z.", 'error')
|
||||
self.addMessage('<a href="https://github.com/ciromattia/kcc#7-zip">Install 7z (link)</a>'
|
||||
' to enable metadata editing.', 'warning')
|
||||
if fname[0] != '':
|
||||
if sys.platform.startswith('win'):
|
||||
sname = fname[0].replace('/', '\\')
|
||||
@@ -547,7 +554,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
||||
self.conversionAlive = False
|
||||
self.worker.sync()
|
||||
icon = QtGui.QIcon()
|
||||
icon.addPixmap(QtGui.QPixmap(":/Other/icons/convert.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||
icon.addPixmap(QtGui.QPixmap(":/Other/icons/convert.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
|
||||
GUI.convertButton.setIcon(icon)
|
||||
GUI.convertButton.setText('Convert')
|
||||
GUI.centralWidget.setAcceptDrops(True)
|
||||
@@ -555,7 +562,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
||||
self.conversionAlive = True
|
||||
self.worker.sync()
|
||||
icon = QtGui.QIcon()
|
||||
icon.addPixmap(QtGui.QPixmap(":/Other/icons/clear.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||
icon.addPixmap(QtGui.QPixmap(":/Other/icons/clear.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
|
||||
GUI.convertButton.setIcon(icon)
|
||||
GUI.convertButton.setText('Abort')
|
||||
GUI.centralWidget.setAcceptDrops(False)
|
||||
@@ -635,6 +642,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
||||
self.modeChange(2)
|
||||
else:
|
||||
self.modeChange(1)
|
||||
GUI.colorBox.setChecked(profile['ForceColor'])
|
||||
self.changeFormat()
|
||||
GUI.gammaSlider.setValue(0)
|
||||
self.changeGamma(0)
|
||||
@@ -669,7 +677,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
||||
|
||||
def addMessage(self, message, icon, replace=False):
|
||||
if icon != '':
|
||||
icon = eval('self.icons.' + icon)
|
||||
icon = getattr(self.icons, icon)
|
||||
item = QtWidgets.QListWidgetItem(icon, ' ' + self.stripTags(message))
|
||||
else:
|
||||
item = QtWidgets.QListWidgetItem(' ' + self.stripTags(message))
|
||||
@@ -687,7 +695,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
||||
|
||||
def showDialog(self, message, kind):
|
||||
if kind == 'error':
|
||||
QtWidgets.QMessageBox.critical(MW, 'KCC - Error', message, QtWidgets.QMessageBox.Ok)
|
||||
QtWidgets.QMessageBox.critical(MW, 'KCC - Error', message, QtWidgets.QMessageBox.StandardButton.Ok)
|
||||
elif kind == 'question':
|
||||
GUI.versionCheck.setAnswer(QtWidgets.QMessageBox.question(MW, 'KCC - Question', message,
|
||||
QtWidgets.QMessageBox.Yes,
|
||||
@@ -715,7 +723,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
||||
self.conversionAlive = False
|
||||
self.worker.sync()
|
||||
else:
|
||||
if QtWidgets.QApplication.keyboardModifiers() == QtCore.Qt.ShiftModifier:
|
||||
if QtWidgets.QApplication.keyboardModifiers() == QtCore.Qt.KeyboardModifier.ShiftModifier:
|
||||
dname = QtWidgets.QFileDialog.getExistingDirectory(MW, 'Select output directory', self.lastPath)
|
||||
if dname != '':
|
||||
if sys.platform.startswith('win'):
|
||||
@@ -749,7 +757,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
||||
|
||||
def display_kindlegen_missing(self):
|
||||
self.addMessage(
|
||||
'<a href="https://github.com/ciromattia/kcc#kindlegen"><b>Install KindleGen (link)</b></a> to enable MOBI conversion for Kindles!',
|
||||
'<a href="https://github.com/ciromattia/kcc#kindlegen"><b>Install KindleGen (link)</b></a> to enable MOBI conversion for Kindles!',
|
||||
'error'
|
||||
)
|
||||
|
||||
@@ -768,23 +776,24 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
||||
self.settings.setValue('currentFormat', GUI.formatBox.currentIndex())
|
||||
self.settings.setValue('startNumber', self.startNumber + 1)
|
||||
self.settings.setValue('windowSize', str(MW.size().width()) + 'x' + str(MW.size().height()))
|
||||
self.settings.setValue('options', {'mangaBox': GUI.mangaBox.checkState(),
|
||||
'rotateBox': GUI.rotateBox.checkState(),
|
||||
'qualityBox': GUI.qualityBox.checkState(),
|
||||
'gammaBox': GUI.gammaBox.checkState(),
|
||||
'croppingBox': GUI.croppingBox.checkState(),
|
||||
self.settings.setValue('options', {'mangaBox': GUI.mangaBox.checkState().value,
|
||||
'rotateBox': GUI.rotateBox.checkState().value,
|
||||
'qualityBox': GUI.qualityBox.checkState().value,
|
||||
'gammaBox': GUI.gammaBox.checkState().value,
|
||||
'croppingBox': GUI.croppingBox.checkState().value,
|
||||
'croppingPowerSlider': float(self.croppingPowerValue) * 100,
|
||||
'upscaleBox': GUI.upscaleBox.checkState(),
|
||||
'borderBox': GUI.borderBox.checkState(),
|
||||
'webtoonBox': GUI.webtoonBox.checkState(),
|
||||
'outputSplit': GUI.outputSplit.checkState(),
|
||||
'colorBox': GUI.colorBox.checkState(),
|
||||
'disableProcessingBox': GUI.disableProcessingBox.checkState(),
|
||||
'mozJpegBox': GUI.mozJpegBox.checkState(),
|
||||
'upscaleBox': GUI.upscaleBox.checkState().value,
|
||||
'borderBox': GUI.borderBox.checkState().value,
|
||||
'webtoonBox': GUI.webtoonBox.checkState().value,
|
||||
'outputSplit': GUI.outputSplit.checkState().value,
|
||||
'colorBox': GUI.colorBox.checkState().value,
|
||||
'disableProcessingBox': GUI.disableProcessingBox.checkState().value,
|
||||
'mozJpegBox': GUI.mozJpegBox.checkState().value,
|
||||
'widthBox': GUI.widthBox.value(),
|
||||
'heightBox': GUI.heightBox.value(),
|
||||
'deleteBox': GUI.deleteBox.checkState(),
|
||||
'maximizeStrips': GUI.maximizeStrips.checkState(),
|
||||
'deleteBox': GUI.deleteBox.checkState().value,
|
||||
'dedupeCoverBox': GUI.dedupeCoverBox.checkState().value,
|
||||
'maximizeStrips': GUI.maximizeStrips.checkState().value,
|
||||
'gammaSlider': float(self.gammaValue) * 100})
|
||||
self.settings.sync()
|
||||
self.tray.hide()
|
||||
@@ -799,7 +808,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
||||
self.needClean = False
|
||||
GUI.jobList.clear()
|
||||
formats = ['.pdf']
|
||||
if self.sevenzip:
|
||||
if self.tar or self.sevenzip:
|
||||
formats.extend(['.cb7', '.7z', '.cbz', '.zip', '.cbr', '.rar'])
|
||||
if os.path.isdir(message):
|
||||
GUI.jobList.addItem(message)
|
||||
@@ -837,12 +846,12 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
versionCheck = subprocess_run_silent(['kindlegen', '-locale', 'en'], stdout=PIPE, stderr=STDOUT, encoding='UTF-8')
|
||||
versionCheck = subprocess_run(['kindlegen', '-locale', 'en'], stdout=PIPE, stderr=STDOUT, encoding='UTF-8')
|
||||
self.kindleGen = True
|
||||
for line in versionCheck.stdout.splitlines():
|
||||
if 'Amazon kindlegen' in line:
|
||||
versionCheck = line.split('V')[1].split(' ')[0]
|
||||
if StrictVersion(versionCheck) < StrictVersion('2.9'):
|
||||
if Version(versionCheck) < Version('2.9'):
|
||||
self.addMessage('Your <a href="https://www.amazon.com/b?node=23496309011">KindleGen</a>'
|
||||
' is outdated! MOBI conversion might fail.', 'warning')
|
||||
break
|
||||
@@ -859,7 +868,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
||||
self.setupUi(MW)
|
||||
self.editor = KCCGUI_MetaEditor()
|
||||
self.icons = Icons()
|
||||
self.settings = QtCore.QSettings('KindleComicConverter', 'KindleComicConverter')
|
||||
self.settings = QtCore.QSettings('ciromattia', 'kcc')
|
||||
self.settingsVersion = self.settings.value('settingsVersion', '', type=str)
|
||||
self.lastPath = self.settings.value('lastPath', '', type=str)
|
||||
self.lastDevice = self.settings.value('lastDevice', 0, type=int)
|
||||
@@ -892,10 +901,10 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
||||
elif sys.platform.startswith('darwin'):
|
||||
for element in ['editorButton', 'wikiButton', 'directoryButton', 'clearButton', 'fileButton', 'deviceBox',
|
||||
'convertButton', 'formatBox']:
|
||||
eval('GUI.' + element).setMinimumSize(QtCore.QSize(0, 0))
|
||||
getattr(GUI, element).setMinimumSize(QtCore.QSize(0, 0))
|
||||
GUI.gridLayout.setContentsMargins(-1, -1, -1, -1)
|
||||
for element in ['gridLayout_2', 'gridLayout_3', 'gridLayout_4', 'horizontalLayout', 'horizontalLayout_2']:
|
||||
eval('GUI.' + element).setContentsMargins(-1, 0, -1, 0)
|
||||
getattr(GUI, element).setContentsMargins(-1, 0, -1, 0)
|
||||
if self.windowSize == '0x0':
|
||||
MW.resize(500, 500)
|
||||
|
||||
@@ -910,94 +919,108 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
||||
|
||||
|
||||
self.profiles = {
|
||||
"Kindle Oasis 2/3": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
||||
'DefaultUpscale': True, 'Label': 'KO'},
|
||||
"Kindle Oasis": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
||||
'DefaultUpscale': True, 'Label': 'KV'},
|
||||
"Kindle Oasis 9/10": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
||||
'DefaultUpscale': True, 'ForceColor': False, 'Label': 'KO'},
|
||||
"Kindle Oasis 8": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
||||
'DefaultUpscale': True, 'ForceColor': False, 'Label': 'KV'},
|
||||
"Kindle Voyage": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
||||
'DefaultUpscale': True, 'Label': 'KV'},
|
||||
'DefaultUpscale': True, 'ForceColor': False, 'Label': 'KV'},
|
||||
"Kindle Scribe": {
|
||||
'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0, 'DefaultUpscale': False, 'Label': 'KS',
|
||||
'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0, 'DefaultUpscale': False, 'ForceColor': False, 'Label': 'KS',
|
||||
},
|
||||
"Kindle 11": {
|
||||
'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0, 'DefaultUpscale': True, 'Label': 'K11',
|
||||
"Kindle 11/12": {
|
||||
'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0, 'DefaultUpscale': True, 'ForceColor': False, 'Label': 'K11',
|
||||
},
|
||||
"Kindle PW 5": {
|
||||
'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0, 'DefaultUpscale': True, 'Label': 'KPW5',
|
||||
"Kindle PW 11": {
|
||||
'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0, 'DefaultUpscale': True, 'ForceColor': False, '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,
|
||||
'DefaultUpscale': False, 'Label': 'KPW'},
|
||||
"Kindle PW 12": {
|
||||
'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0, 'DefaultUpscale': True, 'ForceColor': False, 'Label': 'KPW6',
|
||||
},
|
||||
"Kindle CS 12": {
|
||||
'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0, 'DefaultUpscale': True, 'ForceColor': True, 'Label': 'KCS12',
|
||||
},
|
||||
"Kindle PW 7/10": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
||||
'DefaultUpscale': True, 'ForceColor': False, 'Label': 'KV'},
|
||||
"Kindle PW 5/6": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
||||
'DefaultUpscale': False, 'ForceColor': False, 'Label': 'KPW'},
|
||||
"Kindle 4/5/7/8/10": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
||||
'DefaultUpscale': False, 'Label': 'K578'},
|
||||
"Kindle DX/DXG": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 2,
|
||||
'DefaultUpscale': False, 'Label': 'KDX'},
|
||||
'DefaultUpscale': False, 'ForceColor': False, 'Label': 'K578'},
|
||||
"Kindle DX": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 2,
|
||||
'DefaultUpscale': False, 'ForceColor': False, 'Label': 'KDX'},
|
||||
"Kobo Mini/Touch": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1,
|
||||
'DefaultUpscale': False, 'Label': 'KoMT'},
|
||||
'DefaultUpscale': False, 'ForceColor': False, 'Label': 'KoMT'},
|
||||
"Kobo Glo": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1,
|
||||
'DefaultUpscale': False, 'Label': 'KoG'},
|
||||
'DefaultUpscale': False, 'ForceColor': False, 'Label': 'KoG'},
|
||||
"Kobo Glo HD": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1,
|
||||
'DefaultUpscale': False, 'Label': 'KoGHD'},
|
||||
'DefaultUpscale': False, 'ForceColor': False, 'Label': 'KoGHD'},
|
||||
"Kobo Aura": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1,
|
||||
'DefaultUpscale': False, 'Label': 'KoA'},
|
||||
'DefaultUpscale': False, 'ForceColor': False, 'Label': 'KoA'},
|
||||
"Kobo Aura HD": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1,
|
||||
'DefaultUpscale': True, 'Label': 'KoAHD'},
|
||||
'DefaultUpscale': True, 'ForceColor': False, 'Label': 'KoAHD'},
|
||||
"Kobo Aura H2O": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1,
|
||||
'DefaultUpscale': True, 'Label': 'KoAH2O'},
|
||||
'DefaultUpscale': True, 'ForceColor': False, 'Label': 'KoAH2O'},
|
||||
"Kobo Aura ONE": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1,
|
||||
'DefaultUpscale': True, 'Label': 'KoAO'},
|
||||
'DefaultUpscale': True, 'ForceColor': False, 'Label': 'KoAO'},
|
||||
"Kobo Clara HD": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1,
|
||||
'DefaultUpscale': True, 'Label': 'KoC'},
|
||||
'DefaultUpscale': True, 'ForceColor': False, 'Label': 'KoC'},
|
||||
"Kobo Libra H2O": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1,
|
||||
'DefaultUpscale': True, 'Label': 'KoL'},
|
||||
'DefaultUpscale': True, 'ForceColor': False, 'Label': 'KoL'},
|
||||
"Kobo Forma": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1,
|
||||
'DefaultUpscale': True, 'Label': 'KoF'},
|
||||
'DefaultUpscale': True, 'ForceColor': False, 'Label': 'KoF'},
|
||||
"Kindle 1": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 0,
|
||||
'DefaultUpscale': False, 'Label': 'K1'},
|
||||
'DefaultUpscale': False, 'ForceColor': False, 'Label': 'K1'},
|
||||
"Kindle 2": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 0,
|
||||
'DefaultUpscale': False, 'Label': 'K2'},
|
||||
'DefaultUpscale': False, 'ForceColor': False, 'Label': 'K2'},
|
||||
"Kindle Keyboard": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 0,
|
||||
'DefaultUpscale': False, 'Label': 'K34'},
|
||||
'DefaultUpscale': False, 'ForceColor': False, 'Label': 'K34'},
|
||||
"Kindle Touch": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 0,
|
||||
'DefaultUpscale': False, 'Label': 'K34'},
|
||||
"Kobo Nia": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1, 'DefaultUpscale': True,
|
||||
'DefaultUpscale': False, 'ForceColor': False, 'Label': 'K34'},
|
||||
"Kobo Nia": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1, 'DefaultUpscale': True, 'ForceColor': False,
|
||||
'Label': 'KoN'},
|
||||
"Kobo Clara 2E": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1, 'DefaultUpscale': True,
|
||||
"Kobo Clara 2E": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1, 'DefaultUpscale': True, 'ForceColor': False,
|
||||
'Label': 'KoC'},
|
||||
"Kobo Libra 2": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1, 'DefaultUpscale': True,
|
||||
"Kobo Clara Colour": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1, 'DefaultUpscale': True, 'ForceColor': True,
|
||||
'Label': 'KoCC'},
|
||||
"Kobo Libra 2": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1, 'DefaultUpscale': True, 'ForceColor': False,
|
||||
'Label': 'KoL'},
|
||||
"Kobo Sage": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1, 'DefaultUpscale': True,
|
||||
"Kobo Libra Colour": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1, 'DefaultUpscale': True, 'ForceColor': True,
|
||||
'Label': 'KoLC'},
|
||||
"Kobo Sage": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1, 'DefaultUpscale': True, 'ForceColor': False,
|
||||
'Label': 'KoS'},
|
||||
"Kobo Elipsa": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1, 'DefaultUpscale': True,
|
||||
"Kobo Elipsa": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1, 'DefaultUpscale': True, 'ForceColor': False,
|
||||
'Label': 'KoE'},
|
||||
"Other": {'PVOptions': False, 'ForceExpert': True, 'DefaultFormat': 1, 'DefaultUpscale': False,
|
||||
"Other": {'PVOptions': False, 'ForceExpert': True, 'DefaultFormat': 1, 'DefaultUpscale': False, 'ForceColor': False,
|
||||
'Label': 'OTHER'},
|
||||
}
|
||||
profilesGUI = [
|
||||
"Kindle Oasis 2/3",
|
||||
"Kindle PW 5",
|
||||
"Kindle 11",
|
||||
"Kindle Scribe",
|
||||
"Kindle 11/12",
|
||||
"Kindle PW 12",
|
||||
"Kindle CS 12",
|
||||
"Kindle Oasis 9/10",
|
||||
"Separator",
|
||||
"Kobo Clara 2E",
|
||||
"Kobo Clara Colour",
|
||||
"Kobo Sage",
|
||||
"Kobo Libra 2",
|
||||
"Kobo Libra Colour",
|
||||
"Kobo Elipsa",
|
||||
"Kobo Nia",
|
||||
"Separator",
|
||||
"Other",
|
||||
"Separator",
|
||||
"Kindle Oasis",
|
||||
"Kindle PW 11",
|
||||
"Kindle Oasis 8",
|
||||
"Kindle PW 7/10",
|
||||
"Kindle Voyage",
|
||||
"Kindle PW 5/6",
|
||||
"Kindle 4/5/7/8/10",
|
||||
"Kindle Touch",
|
||||
"Kindle Keyboard",
|
||||
"Kindle DX/DXG",
|
||||
"Kindle PW 3/4",
|
||||
"Kindle PW 1/2",
|
||||
"Kindle Voyage",
|
||||
"Kindle DX",
|
||||
"Kindle 2",
|
||||
"Kindle 1",
|
||||
"Kindle 4/5/7/8/10",
|
||||
"Separator",
|
||||
"Kobo Aura",
|
||||
"Kobo Aura ONE",
|
||||
@@ -1015,7 +1038,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
||||
'com/ciromattia/kcc/blob/master/README.md#issues--new-features--donations">DO'
|
||||
'NATE</a> - <a href="http://www.mobileread.com/forums/showthread.php?t=207461'
|
||||
'">FORUM</a></b>')
|
||||
statusBarLabel.setAlignment(QtCore.Qt.AlignCenter)
|
||||
statusBarLabel.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
|
||||
statusBarLabel.setOpenExternalLinks(True)
|
||||
GUI.statusBar.addPermanentWidget(statusBarLabel, 1)
|
||||
|
||||
@@ -1026,12 +1049,18 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
||||
'<a href="https://github.com/ciromattia/kcc/wiki/Important-tips">important tips</a>.',
|
||||
'info')
|
||||
try:
|
||||
subprocess_run_silent(['7z'], stdout=PIPE, stderr=STDOUT)
|
||||
subprocess_run(['tar'], stdout=PIPE, stderr=STDOUT)
|
||||
self.tar = True
|
||||
except FileNotFoundError:
|
||||
self.tar = False
|
||||
try:
|
||||
subprocess_run(['7z'], stdout=PIPE, stderr=STDOUT)
|
||||
self.sevenzip = True
|
||||
except FileNotFoundError:
|
||||
self.sevenzip = False
|
||||
self.addMessage('<a href="https://github.com/ciromattia/kcc#7-zip">Install 7z (link)</a>'
|
||||
' to enable CBZ/CBR/ZIP/etc processing.', 'warning')
|
||||
if not self.tar:
|
||||
self.addMessage('<a href="https://github.com/ciromattia/kcc#7-zip">Install 7z (link)</a>'
|
||||
' to enable CBZ/CBR/ZIP/etc processing.', 'warning')
|
||||
self.detectKindleGen(True)
|
||||
|
||||
APP.messageFromOtherInstance.connect(self.handleMessage)
|
||||
@@ -1073,7 +1102,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
||||
else:
|
||||
GUI.deviceBox.addItem(self.icons.deviceKindle, profile)
|
||||
for f in self.formats:
|
||||
GUI.formatBox.addItem(eval('self.icons.' + self.formats[f]['icon'] + 'Format'), f)
|
||||
GUI.formatBox.addItem(getattr(self.icons, self.formats[f]['icon'] + 'Format'), f)
|
||||
if self.lastDevice > GUI.deviceBox.count():
|
||||
self.lastDevice = 0
|
||||
if profilesGUI[self.lastDevice] == "Separator":
|
||||
@@ -1099,8 +1128,8 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
||||
self.changeCroppingPower(int(self.options[option]))
|
||||
else:
|
||||
try:
|
||||
if eval('GUI.' + str(option)).isEnabled():
|
||||
eval('GUI.' + str(option)).setCheckState(self.options[option])
|
||||
if getattr(GUI, option).isEnabled():
|
||||
getattr(GUI, option).setCheckState(Qt.CheckState(self.options[option]))
|
||||
except AttributeError:
|
||||
pass
|
||||
self.worker.sync()
|
||||
@@ -1174,7 +1203,7 @@ class KCCGUI_MetaEditor(KCC_ui_editor.Ui_editorDialog):
|
||||
self.ui = QtWidgets.QDialog()
|
||||
self.parser = None
|
||||
self.setupUi(self.ui)
|
||||
self.ui.setWindowFlags(self.ui.windowFlags() & ~QtCore.Qt.WindowContextHelpButtonHint)
|
||||
self.ui.setWindowFlags(self.ui.windowFlags() & ~QtCore.Qt.WindowType.WindowContextHelpButtonHint)
|
||||
self.okButton.clicked.connect(self.saveData)
|
||||
self.cancelButton.clicked.connect(self.ui.close)
|
||||
if sys.platform.startswith('linux'):
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,321 +1,463 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Form implementation generated from reading ui file 'gui/KCC.ui'
|
||||
#
|
||||
# Created by: PyQt5 UI code generator 5.15.7
|
||||
#
|
||||
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
|
||||
# run again. Do not edit this file unless you know what you are doing.
|
||||
|
||||
|
||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||
################################################################################
|
||||
## Form generated from reading UI file 'KCC.ui'
|
||||
##
|
||||
## Created by: Qt User Interface Compiler version 6.5.2
|
||||
##
|
||||
## WARNING! All changes made in this file will be lost when recompiling UI file!
|
||||
################################################################################
|
||||
|
||||
from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
|
||||
QMetaObject, QObject, QPoint, QRect,
|
||||
QSize, QTime, QUrl, Qt)
|
||||
from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
|
||||
QFont, QFontDatabase, QGradient, QIcon,
|
||||
QImage, QKeySequence, QLinearGradient, QPainter,
|
||||
QPalette, QPixmap, QRadialGradient, QTransform)
|
||||
from PySide6.QtWidgets import (QAbstractItemView, QApplication, QCheckBox, QComboBox,
|
||||
QGridLayout, QHBoxLayout, QLabel, QListWidget,
|
||||
QListWidgetItem, QMainWindow, QProgressBar, QPushButton,
|
||||
QSizePolicy, QSlider, QSpinBox, QStatusBar,
|
||||
QWidget)
|
||||
from . import KCC_rc
|
||||
|
||||
class Ui_mainWindow(object):
|
||||
def setupUi(self, mainWindow):
|
||||
mainWindow.setObjectName("mainWindow")
|
||||
if not mainWindow.objectName():
|
||||
mainWindow.setObjectName(u"mainWindow")
|
||||
mainWindow.resize(450, 400)
|
||||
icon = QtGui.QIcon()
|
||||
icon.addPixmap(QtGui.QPixmap(":/Icon/icons/comic2ebook.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||
icon = QIcon()
|
||||
icon.addFile(u":/Icon/icons/comic2ebook.png", QSize(), QIcon.Normal, QIcon.Off)
|
||||
mainWindow.setWindowIcon(icon)
|
||||
self.centralWidget = QtWidgets.QWidget(mainWindow)
|
||||
self.centralWidget.setObjectName("centralWidget")
|
||||
self.gridLayout = QtWidgets.QGridLayout(self.centralWidget)
|
||||
self.centralWidget = QWidget(mainWindow)
|
||||
self.centralWidget.setObjectName(u"centralWidget")
|
||||
self.gridLayout = QGridLayout(self.centralWidget)
|
||||
self.gridLayout.setObjectName(u"gridLayout")
|
||||
self.gridLayout.setContentsMargins(-1, -1, -1, 5)
|
||||
self.gridLayout.setObjectName("gridLayout")
|
||||
self.optionWidget = QtWidgets.QWidget(self.centralWidget)
|
||||
self.optionWidget.setObjectName("optionWidget")
|
||||
self.gridLayout_2 = QtWidgets.QGridLayout(self.optionWidget)
|
||||
self.optionWidget = QWidget(self.centralWidget)
|
||||
self.optionWidget.setObjectName(u"optionWidget")
|
||||
self.gridLayout_2 = QGridLayout(self.optionWidget)
|
||||
self.gridLayout_2.setObjectName(u"gridLayout_2")
|
||||
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 = QCheckBox(self.optionWidget)
|
||||
self.qualityBox.setObjectName(u"qualityBox")
|
||||
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.deleteBox = QtWidgets.QCheckBox(self.optionWidget)
|
||||
self.deleteBox.setObjectName("deleteBox")
|
||||
|
||||
self.deleteBox = QCheckBox(self.optionWidget)
|
||||
self.deleteBox.setObjectName(u"deleteBox")
|
||||
|
||||
self.gridLayout_2.addWidget(self.deleteBox, 4, 1, 1, 1)
|
||||
self.disableProcessingBox = QtWidgets.QCheckBox(self.optionWidget)
|
||||
self.disableProcessingBox.setObjectName("disableProcessingBox")
|
||||
|
||||
self.maximizeStrips = QCheckBox(self.optionWidget)
|
||||
self.maximizeStrips.setObjectName(u"maximizeStrips")
|
||||
|
||||
self.gridLayout_2.addWidget(self.maximizeStrips, 3, 1, 1, 1)
|
||||
|
||||
self.gammaBox = QCheckBox(self.optionWidget)
|
||||
self.gammaBox.setObjectName(u"gammaBox")
|
||||
|
||||
self.gridLayout_2.addWidget(self.gammaBox, 1, 2, 1, 1)
|
||||
|
||||
self.borderBox = QCheckBox(self.optionWidget)
|
||||
self.borderBox.setObjectName(u"borderBox")
|
||||
self.borderBox.setTristate(True)
|
||||
|
||||
self.gridLayout_2.addWidget(self.borderBox, 2, 0, 1, 1)
|
||||
|
||||
self.webtoonBox = QCheckBox(self.optionWidget)
|
||||
self.webtoonBox.setObjectName(u"webtoonBox")
|
||||
|
||||
self.gridLayout_2.addWidget(self.webtoonBox, 1, 0, 1, 1)
|
||||
|
||||
self.upscaleBox = QCheckBox(self.optionWidget)
|
||||
self.upscaleBox.setObjectName(u"upscaleBox")
|
||||
self.upscaleBox.setTristate(True)
|
||||
|
||||
self.gridLayout_2.addWidget(self.upscaleBox, 1, 1, 1, 1)
|
||||
|
||||
self.mangaBox = QCheckBox(self.optionWidget)
|
||||
self.mangaBox.setObjectName(u"mangaBox")
|
||||
|
||||
self.gridLayout_2.addWidget(self.mangaBox, 0, 0, 1, 1)
|
||||
|
||||
self.rotateBox = QCheckBox(self.optionWidget)
|
||||
self.rotateBox.setObjectName(u"rotateBox")
|
||||
self.rotateBox.setTristate(True)
|
||||
|
||||
self.gridLayout_2.addWidget(self.rotateBox, 0, 1, 1, 1)
|
||||
|
||||
self.croppingBox = QCheckBox(self.optionWidget)
|
||||
self.croppingBox.setObjectName(u"croppingBox")
|
||||
self.croppingBox.setTristate(True)
|
||||
|
||||
self.gridLayout_2.addWidget(self.croppingBox, 3, 2, 1, 1)
|
||||
|
||||
self.outputSplit = QCheckBox(self.optionWidget)
|
||||
self.outputSplit.setObjectName(u"outputSplit")
|
||||
|
||||
self.gridLayout_2.addWidget(self.outputSplit, 2, 1, 1, 1)
|
||||
|
||||
self.mozJpegBox = QCheckBox(self.optionWidget)
|
||||
self.mozJpegBox.setObjectName(u"mozJpegBox")
|
||||
self.mozJpegBox.setTristate(True)
|
||||
|
||||
self.gridLayout_2.addWidget(self.mozJpegBox, 3, 0, 1, 1)
|
||||
|
||||
self.colorBox = QCheckBox(self.optionWidget)
|
||||
self.colorBox.setObjectName(u"colorBox")
|
||||
|
||||
self.gridLayout_2.addWidget(self.colorBox, 2, 2, 1, 1)
|
||||
|
||||
self.disableProcessingBox = QCheckBox(self.optionWidget)
|
||||
self.disableProcessingBox.setObjectName(u"disableProcessingBox")
|
||||
|
||||
self.gridLayout_2.addWidget(self.disableProcessingBox, 4, 2, 1, 1)
|
||||
|
||||
self.dedupeCoverBox = QCheckBox(self.optionWidget)
|
||||
self.dedupeCoverBox.setObjectName(u"dedupeCoverBox")
|
||||
|
||||
self.gridLayout_2.addWidget(self.dedupeCoverBox, 4, 0, 1, 1)
|
||||
|
||||
|
||||
self.gridLayout.addWidget(self.optionWidget, 5, 0, 1, 2)
|
||||
self.gammaWidget = QtWidgets.QWidget(self.centralWidget)
|
||||
|
||||
self.gammaWidget = QWidget(self.centralWidget)
|
||||
self.gammaWidget.setObjectName(u"gammaWidget")
|
||||
self.gammaWidget.setVisible(False)
|
||||
self.gammaWidget.setObjectName("gammaWidget")
|
||||
self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.gammaWidget)
|
||||
self.horizontalLayout_2 = QHBoxLayout(self.gammaWidget)
|
||||
self.horizontalLayout_2.setObjectName(u"horizontalLayout_2")
|
||||
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.gammaLabel = QLabel(self.gammaWidget)
|
||||
self.gammaLabel.setObjectName(u"gammaLabel")
|
||||
|
||||
self.horizontalLayout_2.addWidget(self.gammaLabel)
|
||||
self.gammaSlider = QtWidgets.QSlider(self.gammaWidget)
|
||||
|
||||
self.gammaSlider = QSlider(self.gammaWidget)
|
||||
self.gammaSlider.setObjectName(u"gammaSlider")
|
||||
self.gammaSlider.setMaximum(250)
|
||||
self.gammaSlider.setSingleStep(5)
|
||||
self.gammaSlider.setOrientation(QtCore.Qt.Horizontal)
|
||||
self.gammaSlider.setObjectName("gammaSlider")
|
||||
self.gammaSlider.setOrientation(Qt.Horizontal)
|
||||
|
||||
self.horizontalLayout_2.addWidget(self.gammaSlider)
|
||||
|
||||
|
||||
self.gridLayout.addWidget(self.gammaWidget, 6, 0, 1, 2)
|
||||
self.croppingWidget = QtWidgets.QWidget(self.centralWidget)
|
||||
|
||||
self.croppingWidget = QWidget(self.centralWidget)
|
||||
self.croppingWidget.setObjectName(u"croppingWidget")
|
||||
self.croppingWidget.setVisible(False)
|
||||
self.croppingWidget.setObjectName("croppingWidget")
|
||||
self.horizontalLayout_3 = QtWidgets.QHBoxLayout(self.croppingWidget)
|
||||
self.horizontalLayout_3 = QHBoxLayout(self.croppingWidget)
|
||||
self.horizontalLayout_3.setObjectName(u"horizontalLayout_3")
|
||||
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.croppingPowerLabel = QLabel(self.croppingWidget)
|
||||
self.croppingPowerLabel.setObjectName(u"croppingPowerLabel")
|
||||
|
||||
self.horizontalLayout_3.addWidget(self.croppingPowerLabel)
|
||||
self.croppingPowerSlider = QtWidgets.QSlider(self.croppingWidget)
|
||||
|
||||
self.croppingPowerSlider = QSlider(self.croppingWidget)
|
||||
self.croppingPowerSlider.setObjectName(u"croppingPowerSlider")
|
||||
self.croppingPowerSlider.setMaximum(200)
|
||||
self.croppingPowerSlider.setSingleStep(1)
|
||||
self.croppingPowerSlider.setOrientation(QtCore.Qt.Horizontal)
|
||||
self.croppingPowerSlider.setObjectName("croppingPowerSlider")
|
||||
self.croppingPowerSlider.setOrientation(Qt.Horizontal)
|
||||
|
||||
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)
|
||||
|
||||
self.buttonWidget = QWidget(self.centralWidget)
|
||||
self.buttonWidget.setObjectName(u"buttonWidget")
|
||||
sizePolicy = QSizePolicy(QSizePolicy.Preferred, 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 = QGridLayout(self.buttonWidget)
|
||||
self.gridLayout_4.setObjectName(u"gridLayout_4")
|
||||
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 = QPushButton(self.buttonWidget)
|
||||
self.directoryButton.setObjectName(u"directoryButton")
|
||||
self.directoryButton.setMinimumSize(QSize(0, 30))
|
||||
icon1 = QIcon()
|
||||
icon1.addFile(u":/Other/icons/folder_new.png", QSize(), QIcon.Normal, 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 = QPushButton(self.buttonWidget)
|
||||
self.fileButton.setObjectName(u"fileButton")
|
||||
self.fileButton.setMinimumSize(QSize(0, 30))
|
||||
icon2 = QIcon()
|
||||
icon2.addFile(u":/Other/icons/document_new.png", QSize(), QIcon.Normal, 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.deviceBox = QComboBox(self.buttonWidget)
|
||||
self.deviceBox.setObjectName(u"deviceBox")
|
||||
self.deviceBox.setMinimumSize(QSize(0, 28))
|
||||
|
||||
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.formatBox = QComboBox(self.buttonWidget)
|
||||
self.formatBox.setObjectName(u"formatBox")
|
||||
self.formatBox.setMinimumSize(QSize(0, 28))
|
||||
|
||||
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()
|
||||
|
||||
self.convertButton = QPushButton(self.buttonWidget)
|
||||
self.convertButton.setObjectName(u"convertButton")
|
||||
self.convertButton.setMinimumSize(QSize(0, 30))
|
||||
font = QFont()
|
||||
font.setBold(True)
|
||||
self.convertButton.setFont(font)
|
||||
icon3 = QtGui.QIcon()
|
||||
icon3.addPixmap(QtGui.QPixmap(":/Other/icons/convert.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||
icon3 = QIcon()
|
||||
icon3.addFile(u":/Other/icons/convert.png", QSize(), QIcon.Normal, QIcon.Off)
|
||||
self.convertButton.setIcon(icon3)
|
||||
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))
|
||||
icon4 = QtGui.QIcon()
|
||||
icon4.addPixmap(QtGui.QPixmap(":/Other/icons/clear.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||
|
||||
self.clearButton = QPushButton(self.buttonWidget)
|
||||
self.clearButton.setObjectName(u"clearButton")
|
||||
self.clearButton.setMinimumSize(QSize(0, 30))
|
||||
icon4 = QIcon()
|
||||
icon4.addFile(u":/Other/icons/clear.png", QSize(), QIcon.Normal, 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.toolWidget = QWidget(self.centralWidget)
|
||||
self.toolWidget.setObjectName(u"toolWidget")
|
||||
self.horizontalLayout = QHBoxLayout(self.toolWidget)
|
||||
self.horizontalLayout.setObjectName(u"horizontalLayout")
|
||||
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 = QPushButton(self.toolWidget)
|
||||
self.editorButton.setObjectName(u"editorButton")
|
||||
self.editorButton.setMinimumSize(QSize(0, 30))
|
||||
icon5 = QIcon()
|
||||
icon5.addFile(u":/Other/icons/editor.png", QSize(), QIcon.Normal, 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 = QPushButton(self.toolWidget)
|
||||
self.wikiButton.setObjectName(u"wikiButton")
|
||||
self.wikiButton.setMinimumSize(QSize(0, 30))
|
||||
icon6 = QIcon()
|
||||
icon6.addFile(u":/Other/icons/wiki.png", QSize(), QIcon.Normal, 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.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.setVerticalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel)
|
||||
self.jobList.setHorizontalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel)
|
||||
self.jobList.setObjectName("jobList")
|
||||
|
||||
self.jobList = QListWidget(self.centralWidget)
|
||||
self.jobList.setObjectName(u"jobList")
|
||||
self.jobList.setStyleSheet(u"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(QAbstractItemView.NoSelection)
|
||||
self.jobList.setVerticalScrollMode(QAbstractItemView.ScrollPerPixel)
|
||||
self.jobList.setHorizontalScrollMode(QAbstractItemView.ScrollPerPixel)
|
||||
|
||||
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 = QProgressBar(self.centralWidget)
|
||||
self.progressBar.setObjectName(u"progressBar")
|
||||
self.progressBar.setMinimumSize(QSize(0, 30))
|
||||
self.progressBar.setFont(font)
|
||||
self.progressBar.setVisible(False)
|
||||
self.progressBar.setAlignment(QtCore.Qt.AlignJustify|QtCore.Qt.AlignVCenter)
|
||||
self.progressBar.setObjectName("progressBar")
|
||||
self.progressBar.setAlignment(Qt.AlignJustify|Qt.AlignVCenter)
|
||||
|
||||
self.gridLayout.addWidget(self.progressBar, 1, 0, 1, 2)
|
||||
self.customWidget = QtWidgets.QWidget(self.centralWidget)
|
||||
|
||||
self.customWidget = QWidget(self.centralWidget)
|
||||
self.customWidget.setObjectName(u"customWidget")
|
||||
self.customWidget.setVisible(False)
|
||||
self.customWidget.setObjectName("customWidget")
|
||||
self.gridLayout_3 = QtWidgets.QGridLayout(self.customWidget)
|
||||
self.gridLayout_3 = QGridLayout(self.customWidget)
|
||||
self.gridLayout_3.setObjectName(u"gridLayout_3")
|
||||
self.gridLayout_3.setContentsMargins(0, 0, 0, 0)
|
||||
self.gridLayout_3.setObjectName("gridLayout_3")
|
||||
self.hLabel = QtWidgets.QLabel(self.customWidget)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Preferred)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.hLabel.sizePolicy().hasHeightForWidth())
|
||||
self.hLabel.setSizePolicy(sizePolicy)
|
||||
self.hLabel.setObjectName("hLabel")
|
||||
self.hLabel = QLabel(self.customWidget)
|
||||
self.hLabel.setObjectName(u"hLabel")
|
||||
sizePolicy1 = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Preferred)
|
||||
sizePolicy1.setHorizontalStretch(0)
|
||||
sizePolicy1.setVerticalStretch(0)
|
||||
sizePolicy1.setHeightForWidth(self.hLabel.sizePolicy().hasHeightForWidth())
|
||||
self.hLabel.setSizePolicy(sizePolicy1)
|
||||
|
||||
self.gridLayout_3.addWidget(self.hLabel, 0, 2, 1, 1)
|
||||
self.widthBox = QtWidgets.QSpinBox(self.customWidget)
|
||||
|
||||
self.widthBox = QSpinBox(self.customWidget)
|
||||
self.widthBox.setObjectName(u"widthBox")
|
||||
self.widthBox.setMaximum(2160)
|
||||
self.widthBox.setObjectName("widthBox")
|
||||
|
||||
self.gridLayout_3.addWidget(self.widthBox, 0, 1, 1, 1)
|
||||
self.wLabel = QtWidgets.QLabel(self.customWidget)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Preferred)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.wLabel.sizePolicy().hasHeightForWidth())
|
||||
self.wLabel.setSizePolicy(sizePolicy)
|
||||
self.wLabel.setObjectName("wLabel")
|
||||
|
||||
self.wLabel = QLabel(self.customWidget)
|
||||
self.wLabel.setObjectName(u"wLabel")
|
||||
sizePolicy1.setHeightForWidth(self.wLabel.sizePolicy().hasHeightForWidth())
|
||||
self.wLabel.setSizePolicy(sizePolicy1)
|
||||
|
||||
self.gridLayout_3.addWidget(self.wLabel, 0, 0, 1, 1)
|
||||
self.heightBox = QtWidgets.QSpinBox(self.customWidget)
|
||||
|
||||
self.heightBox = QSpinBox(self.customWidget)
|
||||
self.heightBox.setObjectName(u"heightBox")
|
||||
self.heightBox.setMaximum(3840)
|
||||
self.heightBox.setObjectName("heightBox")
|
||||
|
||||
self.gridLayout_3.addWidget(self.heightBox, 0, 3, 1, 1)
|
||||
|
||||
|
||||
self.gridLayout.addWidget(self.customWidget, 7, 0, 1, 2)
|
||||
|
||||
mainWindow.setCentralWidget(self.centralWidget)
|
||||
self.statusBar = QtWidgets.QStatusBar(mainWindow)
|
||||
self.statusBar = QStatusBar(mainWindow)
|
||||
self.statusBar.setObjectName(u"statusBar")
|
||||
self.statusBar.setSizeGripEnabled(False)
|
||||
self.statusBar.setObjectName("statusBar")
|
||||
mainWindow.setStatusBar(self.statusBar)
|
||||
QWidget.setTabOrder(self.convertButton, self.clearButton)
|
||||
QWidget.setTabOrder(self.clearButton, self.directoryButton)
|
||||
QWidget.setTabOrder(self.directoryButton, self.fileButton)
|
||||
QWidget.setTabOrder(self.fileButton, self.deviceBox)
|
||||
QWidget.setTabOrder(self.deviceBox, self.formatBox)
|
||||
QWidget.setTabOrder(self.formatBox, self.mangaBox)
|
||||
QWidget.setTabOrder(self.mangaBox, self.rotateBox)
|
||||
QWidget.setTabOrder(self.rotateBox, self.qualityBox)
|
||||
QWidget.setTabOrder(self.qualityBox, self.webtoonBox)
|
||||
QWidget.setTabOrder(self.webtoonBox, self.upscaleBox)
|
||||
QWidget.setTabOrder(self.upscaleBox, self.gammaBox)
|
||||
QWidget.setTabOrder(self.gammaBox, self.borderBox)
|
||||
QWidget.setTabOrder(self.borderBox, self.outputSplit)
|
||||
QWidget.setTabOrder(self.outputSplit, self.colorBox)
|
||||
QWidget.setTabOrder(self.colorBox, self.croppingBox)
|
||||
QWidget.setTabOrder(self.croppingBox, self.mozJpegBox)
|
||||
QWidget.setTabOrder(self.mozJpegBox, self.maximizeStrips)
|
||||
QWidget.setTabOrder(self.maximizeStrips, self.deleteBox)
|
||||
QWidget.setTabOrder(self.deleteBox, self.disableProcessingBox)
|
||||
QWidget.setTabOrder(self.disableProcessingBox, self.editorButton)
|
||||
QWidget.setTabOrder(self.editorButton, self.wikiButton)
|
||||
QWidget.setTabOrder(self.wikiButton, self.jobList)
|
||||
QWidget.setTabOrder(self.jobList, self.gammaSlider)
|
||||
QWidget.setTabOrder(self.gammaSlider, self.widthBox)
|
||||
QWidget.setTabOrder(self.widthBox, self.heightBox)
|
||||
QWidget.setTabOrder(self.heightBox, self.croppingPowerSlider)
|
||||
|
||||
self.retranslateUi(mainWindow)
|
||||
QtCore.QMetaObject.connectSlotsByName(mainWindow)
|
||||
mainWindow.setTabOrder(self.convertButton, self.clearButton)
|
||||
mainWindow.setTabOrder(self.clearButton, self.directoryButton)
|
||||
mainWindow.setTabOrder(self.directoryButton, self.fileButton)
|
||||
mainWindow.setTabOrder(self.fileButton, self.deviceBox)
|
||||
mainWindow.setTabOrder(self.deviceBox, self.formatBox)
|
||||
mainWindow.setTabOrder(self.formatBox, self.mangaBox)
|
||||
mainWindow.setTabOrder(self.mangaBox, self.rotateBox)
|
||||
mainWindow.setTabOrder(self.rotateBox, self.qualityBox)
|
||||
mainWindow.setTabOrder(self.qualityBox, self.webtoonBox)
|
||||
mainWindow.setTabOrder(self.webtoonBox, self.upscaleBox)
|
||||
mainWindow.setTabOrder(self.upscaleBox, self.gammaBox)
|
||||
mainWindow.setTabOrder(self.gammaBox, self.borderBox)
|
||||
mainWindow.setTabOrder(self.borderBox, self.outputSplit)
|
||||
mainWindow.setTabOrder(self.outputSplit, self.colorBox)
|
||||
mainWindow.setTabOrder(self.colorBox, self.croppingBox)
|
||||
mainWindow.setTabOrder(self.croppingBox, self.mozJpegBox)
|
||||
mainWindow.setTabOrder(self.mozJpegBox, self.maximizeStrips)
|
||||
mainWindow.setTabOrder(self.maximizeStrips, self.deleteBox)
|
||||
mainWindow.setTabOrder(self.deleteBox, self.disableProcessingBox)
|
||||
mainWindow.setTabOrder(self.disableProcessingBox, self.editorButton)
|
||||
mainWindow.setTabOrder(self.editorButton, self.wikiButton)
|
||||
mainWindow.setTabOrder(self.wikiButton, self.jobList)
|
||||
mainWindow.setTabOrder(self.jobList, self.gammaSlider)
|
||||
mainWindow.setTabOrder(self.gammaSlider, self.widthBox)
|
||||
mainWindow.setTabOrder(self.widthBox, self.heightBox)
|
||||
mainWindow.setTabOrder(self.heightBox, self.croppingPowerSlider)
|
||||
|
||||
QMetaObject.connectSlotsByName(mainWindow)
|
||||
# setupUi
|
||||
|
||||
def retranslateUi(self, mainWindow):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
mainWindow.setWindowTitle(_translate("mainWindow", "Kindle Comic Converter"))
|
||||
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.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.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.setText(_translate("mainWindow", "W/B margins"))
|
||||
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.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.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.deleteBox.setToolTip(_translate("mainWindow", "Delete input file(s) or directory. It\'s not recoverable!"))
|
||||
self.deleteBox.setText(_translate("mainWindow", "Delete input"))
|
||||
self.disableProcessingBox.setToolTip(_translate("mainWindow", "<html><head/><body><pre style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">Do not process any image, ignore profile and processing options</pre></body></html>"))
|
||||
self.disableProcessingBox.setText(_translate("mainWindow", "Disable processing"))
|
||||
self.gammaLabel.setText(_translate("mainWindow", "Gamma: Auto"))
|
||||
self.croppingPowerLabel.setText(_translate("mainWindow", "Cropping power:"))
|
||||
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.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.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.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.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
|
||||
mainWindow.setWindowTitle(QCoreApplication.translate("mainWindow", u"Kindle Comic Converter", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.qualityBox.setToolTip(QCoreApplication.translate("mainWindow", u"<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>", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.qualityBox.setText(QCoreApplication.translate("mainWindow", u"Panel View 4/2/HQ", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.deleteBox.setToolTip(QCoreApplication.translate("mainWindow", u"Delete input file(s) or directory. It's not recoverable!", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.deleteBox.setText(QCoreApplication.translate("mainWindow", u"Delete input", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.maximizeStrips.setToolTip(QCoreApplication.translate("mainWindow", u"<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>", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.maximizeStrips.setText(QCoreApplication.translate("mainWindow", u"1x4 to 2x2 strips", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.gammaBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p style='white-space:pre'>Disable automatic gamma correction.</p></body></html>", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.gammaBox.setText(QCoreApplication.translate("mainWindow", u"Custom gamma", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.borderBox.setToolTip(QCoreApplication.translate("mainWindow", u"<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>", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.borderBox.setText(QCoreApplication.translate("mainWindow", u"W/B margins", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.webtoonBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p style='white-space:pre'>Enable special parsing mode for Korean Webtoons.</p></body></html>", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.webtoonBox.setText(QCoreApplication.translate("mainWindow", u"Webtoon mode", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.upscaleBox.setToolTip(QCoreApplication.translate("mainWindow", u"<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>", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.upscaleBox.setText(QCoreApplication.translate("mainWindow", u"Stretch/Upscale", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.mangaBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p style='white-space:pre'>Enable right-to-left reading.</p></body></html>", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.mangaBox.setText(QCoreApplication.translate("mainWindow", u"Manga mode", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.rotateBox.setToolTip(QCoreApplication.translate("mainWindow", u"<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>", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.rotateBox.setText(QCoreApplication.translate("mainWindow", u"Spread splitter", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.croppingBox.setToolTip(QCoreApplication.translate("mainWindow", u"<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>", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.croppingBox.setText(QCoreApplication.translate("mainWindow", u"Cropping mode", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.outputSplit.setToolTip(QCoreApplication.translate("mainWindow", u"<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>", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.outputSplit.setText(QCoreApplication.translate("mainWindow", u"Output split", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.mozJpegBox.setToolTip(QCoreApplication.translate("mainWindow", u"<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>", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.mozJpegBox.setText(QCoreApplication.translate("mainWindow", u"JPEG/PNG/mozJpeg", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.colorBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p style='white-space:pre'>Disable conversion to grayscale.</p></body></html>", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.colorBox.setText(QCoreApplication.translate("mainWindow", u"Color mode", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.disableProcessingBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><pre style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">Do not process any image, ignore profile and processing options</pre></body></html>", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.disableProcessingBox.setText(QCoreApplication.translate("mainWindow", u"Disable processing", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.dedupeCoverBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p>Don't duplicate the first page as the cover. Useful for 2 page spread alignment.</p></body></html>", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.dedupeCoverBox.setText(QCoreApplication.translate("mainWindow", u"De-dupe cover", None))
|
||||
self.gammaLabel.setText(QCoreApplication.translate("mainWindow", u"Gamma: Auto", None))
|
||||
self.croppingPowerLabel.setText(QCoreApplication.translate("mainWindow", u"Cropping power:", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.directoryButton.setToolTip(QCoreApplication.translate("mainWindow", u"<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>", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.directoryButton.setText(QCoreApplication.translate("mainWindow", u"Add directory", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.fileButton.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p style='white-space:pre'>Add CBR, CBZ, CB7 or PDF file to queue.</p></body></html>", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.fileButton.setText(QCoreApplication.translate("mainWindow", u"Add file", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.deviceBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p style='white-space:pre'>Target device.</p></body></html>", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.formatBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p style='white-space:pre'>Output format.</p></body></html>", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.convertButton.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p style='white-space:pre'>Shift+Click to select the output directory.</p></body></html>", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.convertButton.setText(QCoreApplication.translate("mainWindow", u"Convert", None))
|
||||
self.clearButton.setText(QCoreApplication.translate("mainWindow", u"Clear list", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.editorButton.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p style='white-space:pre'>Shift+Click to edit directory.</p></body></html>", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.editorButton.setText(QCoreApplication.translate("mainWindow", u"Editor", None))
|
||||
self.wikiButton.setText(QCoreApplication.translate("mainWindow", u"Wiki", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.hLabel.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p style='white-space:pre'>Resolution of the target device.</p></body></html>", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.hLabel.setText(QCoreApplication.translate("mainWindow", u"Custom height:", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.widthBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p style='white-space:pre'>Resolution of the target device.</p></body></html>", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.wLabel.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p style='white-space:pre'>Resolution of the target device.</p></body></html>", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.wLabel.setText(QCoreApplication.translate("mainWindow", u"Custom width:", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.heightBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p style='white-space:pre'>Resolution of the target device.</p></body></html>", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
# retranslateUi
|
||||
|
||||
|
||||
@@ -1,118 +1,168 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Form implementation generated from reading ui file 'gui/MetaEditor.ui'
|
||||
#
|
||||
# Created by: PyQt5 UI code generator 5.15.2
|
||||
#
|
||||
# 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
|
||||
################################################################################
|
||||
## Form generated from reading UI file 'MetaEditor.ui'
|
||||
##
|
||||
## Created by: Qt User Interface Compiler version 6.5.2
|
||||
##
|
||||
## WARNING! All changes made in this file will be lost when recompiling UI file!
|
||||
################################################################################
|
||||
|
||||
from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
|
||||
QMetaObject, QObject, QPoint, QRect,
|
||||
QSize, QTime, QUrl, Qt)
|
||||
from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
|
||||
QFont, QFontDatabase, QGradient, QIcon,
|
||||
QImage, QKeySequence, QLinearGradient, QPainter,
|
||||
QPalette, QPixmap, QRadialGradient, QTransform)
|
||||
from PySide6.QtWidgets import (QApplication, QDialog, QGridLayout, QHBoxLayout,
|
||||
QLabel, QLineEdit, QPushButton, QSizePolicy,
|
||||
QVBoxLayout, QWidget)
|
||||
from . import KCC_rc
|
||||
|
||||
class Ui_editorDialog(object):
|
||||
def setupUi(self, editorDialog):
|
||||
editorDialog.setObjectName("editorDialog")
|
||||
if not editorDialog.objectName():
|
||||
editorDialog.setObjectName(u"editorDialog")
|
||||
editorDialog.resize(400, 260)
|
||||
editorDialog.setMinimumSize(QtCore.QSize(400, 260))
|
||||
icon = QtGui.QIcon()
|
||||
icon.addPixmap(QtGui.QPixmap(":/Icon/icons/comic2ebook.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||
editorDialog.setMinimumSize(QSize(400, 260))
|
||||
icon = QIcon()
|
||||
icon.addFile(u":/Icon/icons/comic2ebook.png", QSize(), QIcon.Normal, QIcon.Off)
|
||||
editorDialog.setWindowIcon(icon)
|
||||
self.verticalLayout = QtWidgets.QVBoxLayout(editorDialog)
|
||||
self.verticalLayout = QVBoxLayout(editorDialog)
|
||||
self.verticalLayout.setObjectName(u"verticalLayout")
|
||||
self.verticalLayout.setContentsMargins(-1, -1, -1, 5)
|
||||
self.verticalLayout.setObjectName("verticalLayout")
|
||||
self.editorWidget = QtWidgets.QWidget(editorDialog)
|
||||
self.editorWidget.setObjectName("editorWidget")
|
||||
self.gridLayout = QtWidgets.QGridLayout(self.editorWidget)
|
||||
self.editorWidget = QWidget(editorDialog)
|
||||
self.editorWidget.setObjectName(u"editorWidget")
|
||||
self.gridLayout = QGridLayout(self.editorWidget)
|
||||
self.gridLayout.setObjectName(u"gridLayout")
|
||||
self.gridLayout.setContentsMargins(0, 0, 0, 0)
|
||||
self.gridLayout.setObjectName("gridLayout")
|
||||
self.label_1 = QtWidgets.QLabel(self.editorWidget)
|
||||
self.label_1.setObjectName("label_1")
|
||||
self.label_1 = QLabel(self.editorWidget)
|
||||
self.label_1.setObjectName(u"label_1")
|
||||
|
||||
self.gridLayout.addWidget(self.label_1, 0, 0, 1, 1)
|
||||
self.seriesLine = QtWidgets.QLineEdit(self.editorWidget)
|
||||
self.seriesLine.setObjectName("seriesLine")
|
||||
|
||||
self.seriesLine = QLineEdit(self.editorWidget)
|
||||
self.seriesLine.setObjectName(u"seriesLine")
|
||||
|
||||
self.gridLayout.addWidget(self.seriesLine, 0, 1, 1, 1)
|
||||
self.label_2 = QtWidgets.QLabel(self.editorWidget)
|
||||
self.label_2.setObjectName("label_2")
|
||||
|
||||
self.label_2 = QLabel(self.editorWidget)
|
||||
self.label_2.setObjectName(u"label_2")
|
||||
|
||||
self.gridLayout.addWidget(self.label_2, 1, 0, 1, 1)
|
||||
self.volumeLine = QtWidgets.QLineEdit(self.editorWidget)
|
||||
self.volumeLine.setObjectName("volumeLine")
|
||||
|
||||
self.volumeLine = QLineEdit(self.editorWidget)
|
||||
self.volumeLine.setObjectName(u"volumeLine")
|
||||
|
||||
self.gridLayout.addWidget(self.volumeLine, 1, 1, 1, 1)
|
||||
self.label_3 = QtWidgets.QLabel(self.editorWidget)
|
||||
self.label_3.setObjectName("label_3")
|
||||
|
||||
self.label_3 = QLabel(self.editorWidget)
|
||||
self.label_3.setObjectName(u"label_3")
|
||||
|
||||
self.gridLayout.addWidget(self.label_3, 2, 0, 1, 1)
|
||||
self.numberLine = QtWidgets.QLineEdit(self.editorWidget)
|
||||
self.numberLine.setObjectName("numberLine")
|
||||
|
||||
self.numberLine = QLineEdit(self.editorWidget)
|
||||
self.numberLine.setObjectName(u"numberLine")
|
||||
|
||||
self.gridLayout.addWidget(self.numberLine, 2, 1, 1, 1)
|
||||
self.label_4 = QtWidgets.QLabel(self.editorWidget)
|
||||
self.label_4.setObjectName("label_4")
|
||||
|
||||
self.label_4 = QLabel(self.editorWidget)
|
||||
self.label_4.setObjectName(u"label_4")
|
||||
|
||||
self.gridLayout.addWidget(self.label_4, 3, 0, 1, 1)
|
||||
self.writerLine = QtWidgets.QLineEdit(self.editorWidget)
|
||||
self.writerLine.setObjectName("writerLine")
|
||||
|
||||
self.writerLine = QLineEdit(self.editorWidget)
|
||||
self.writerLine.setObjectName(u"writerLine")
|
||||
|
||||
self.gridLayout.addWidget(self.writerLine, 3, 1, 1, 1)
|
||||
self.label_5 = QtWidgets.QLabel(self.editorWidget)
|
||||
self.label_5.setObjectName("label_5")
|
||||
|
||||
self.label_5 = QLabel(self.editorWidget)
|
||||
self.label_5.setObjectName(u"label_5")
|
||||
|
||||
self.gridLayout.addWidget(self.label_5, 4, 0, 1, 1)
|
||||
self.pencillerLine = QtWidgets.QLineEdit(self.editorWidget)
|
||||
self.pencillerLine.setObjectName("pencillerLine")
|
||||
|
||||
self.pencillerLine = QLineEdit(self.editorWidget)
|
||||
self.pencillerLine.setObjectName(u"pencillerLine")
|
||||
|
||||
self.gridLayout.addWidget(self.pencillerLine, 4, 1, 1, 1)
|
||||
self.label_6 = QtWidgets.QLabel(self.editorWidget)
|
||||
self.label_6.setObjectName("label_6")
|
||||
|
||||
self.label_6 = QLabel(self.editorWidget)
|
||||
self.label_6.setObjectName(u"label_6")
|
||||
|
||||
self.gridLayout.addWidget(self.label_6, 5, 0, 1, 1)
|
||||
self.inkerLine = QtWidgets.QLineEdit(self.editorWidget)
|
||||
self.inkerLine.setObjectName("inkerLine")
|
||||
|
||||
self.inkerLine = QLineEdit(self.editorWidget)
|
||||
self.inkerLine.setObjectName(u"inkerLine")
|
||||
|
||||
self.gridLayout.addWidget(self.inkerLine, 5, 1, 1, 1)
|
||||
self.label_7 = QtWidgets.QLabel(self.editorWidget)
|
||||
self.label_7.setObjectName("label_7")
|
||||
|
||||
self.label_7 = QLabel(self.editorWidget)
|
||||
self.label_7.setObjectName(u"label_7")
|
||||
|
||||
self.gridLayout.addWidget(self.label_7, 6, 0, 1, 1)
|
||||
self.coloristLine = QtWidgets.QLineEdit(self.editorWidget)
|
||||
self.coloristLine.setObjectName("coloristLine")
|
||||
|
||||
self.coloristLine = QLineEdit(self.editorWidget)
|
||||
self.coloristLine.setObjectName(u"coloristLine")
|
||||
|
||||
self.gridLayout.addWidget(self.coloristLine, 6, 1, 1, 1)
|
||||
|
||||
|
||||
self.verticalLayout.addWidget(self.editorWidget)
|
||||
self.optionWidget = QtWidgets.QWidget(editorDialog)
|
||||
self.optionWidget.setObjectName("optionWidget")
|
||||
self.horizontalLayout = QtWidgets.QHBoxLayout(self.optionWidget)
|
||||
|
||||
self.optionWidget = QWidget(editorDialog)
|
||||
self.optionWidget.setObjectName(u"optionWidget")
|
||||
self.horizontalLayout = QHBoxLayout(self.optionWidget)
|
||||
self.horizontalLayout.setObjectName(u"horizontalLayout")
|
||||
self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
|
||||
self.horizontalLayout.setObjectName("horizontalLayout")
|
||||
self.statusLabel = QtWidgets.QLabel(self.optionWidget)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.MinimumExpanding)
|
||||
self.statusLabel = QLabel(self.optionWidget)
|
||||
self.statusLabel.setObjectName(u"statusLabel")
|
||||
sizePolicy = QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.statusLabel.sizePolicy().hasHeightForWidth())
|
||||
self.statusLabel.setSizePolicy(sizePolicy)
|
||||
self.statusLabel.setText("")
|
||||
self.statusLabel.setObjectName("statusLabel")
|
||||
|
||||
self.horizontalLayout.addWidget(self.statusLabel)
|
||||
self.okButton = QtWidgets.QPushButton(self.optionWidget)
|
||||
self.okButton.setMinimumSize(QtCore.QSize(0, 30))
|
||||
icon1 = QtGui.QIcon()
|
||||
icon1.addPixmap(QtGui.QPixmap(":/Other/icons/convert.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||
|
||||
self.okButton = QPushButton(self.optionWidget)
|
||||
self.okButton.setObjectName(u"okButton")
|
||||
self.okButton.setMinimumSize(QSize(0, 30))
|
||||
icon1 = QIcon()
|
||||
icon1.addFile(u":/Other/icons/convert.png", QSize(), QIcon.Normal, QIcon.Off)
|
||||
self.okButton.setIcon(icon1)
|
||||
self.okButton.setObjectName("okButton")
|
||||
|
||||
self.horizontalLayout.addWidget(self.okButton)
|
||||
self.cancelButton = QtWidgets.QPushButton(self.optionWidget)
|
||||
self.cancelButton.setMinimumSize(QtCore.QSize(0, 30))
|
||||
icon2 = QtGui.QIcon()
|
||||
icon2.addPixmap(QtGui.QPixmap(":/Other/icons/clear.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||
|
||||
self.cancelButton = QPushButton(self.optionWidget)
|
||||
self.cancelButton.setObjectName(u"cancelButton")
|
||||
self.cancelButton.setMinimumSize(QSize(0, 30))
|
||||
icon2 = QIcon()
|
||||
icon2.addFile(u":/Other/icons/clear.png", QSize(), QIcon.Normal, QIcon.Off)
|
||||
self.cancelButton.setIcon(icon2)
|
||||
self.cancelButton.setObjectName("cancelButton")
|
||||
|
||||
self.horizontalLayout.addWidget(self.cancelButton)
|
||||
|
||||
|
||||
self.verticalLayout.addWidget(self.optionWidget)
|
||||
|
||||
|
||||
self.retranslateUi(editorDialog)
|
||||
QtCore.QMetaObject.connectSlotsByName(editorDialog)
|
||||
|
||||
QMetaObject.connectSlotsByName(editorDialog)
|
||||
# setupUi
|
||||
|
||||
def retranslateUi(self, editorDialog):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
editorDialog.setWindowTitle(_translate("editorDialog", "Metadata editor"))
|
||||
self.label_1.setText(_translate("editorDialog", "Series:"))
|
||||
self.label_2.setText(_translate("editorDialog", "Volume:"))
|
||||
self.label_3.setText(_translate("editorDialog", "Number:"))
|
||||
self.label_4.setText(_translate("editorDialog", "Writer:"))
|
||||
self.label_5.setText(_translate("editorDialog", "Penciller:"))
|
||||
self.label_6.setText(_translate("editorDialog", "Inker:"))
|
||||
self.label_7.setText(_translate("editorDialog", "Colorist:"))
|
||||
self.okButton.setText(_translate("editorDialog", "Save"))
|
||||
self.cancelButton.setText(_translate("editorDialog", "Cancel"))
|
||||
from . import KCC_rc
|
||||
editorDialog.setWindowTitle(QCoreApplication.translate("editorDialog", u"Metadata editor", None))
|
||||
self.label_1.setText(QCoreApplication.translate("editorDialog", u"Series:", None))
|
||||
self.label_2.setText(QCoreApplication.translate("editorDialog", u"Volume:", None))
|
||||
self.label_3.setText(QCoreApplication.translate("editorDialog", u"Number:", None))
|
||||
self.label_4.setText(QCoreApplication.translate("editorDialog", u"Writer:", None))
|
||||
self.label_5.setText(QCoreApplication.translate("editorDialog", u"Penciller:", None))
|
||||
self.label_6.setText(QCoreApplication.translate("editorDialog", u"Inker:", None))
|
||||
self.label_7.setText(QCoreApplication.translate("editorDialog", u"Colorist:", None))
|
||||
self.statusLabel.setText("")
|
||||
self.okButton.setText(QCoreApplication.translate("editorDialog", u"Save", None))
|
||||
self.cancelButton.setText(QCoreApplication.translate("editorDialog", u"Cancel", None))
|
||||
# retranslateUi
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
__version__ = '5.6.5'
|
||||
__version__ = '6.2.1'
|
||||
__license__ = 'ISC'
|
||||
__copyright__ = '2012-2022, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>, darodi'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
import os
|
||||
import pathlib
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
from argparse import ArgumentParser
|
||||
from time import strftime, gmtime
|
||||
@@ -36,15 +35,12 @@ from multiprocessing import Pool
|
||||
from uuid import uuid4
|
||||
from natsort import os_sorted
|
||||
from slugify import slugify as slugify_ext
|
||||
from PIL import Image
|
||||
from PIL import Image, ImageFile
|
||||
from subprocess import STDOUT, PIPE
|
||||
from psutil import virtual_memory, disk_usage
|
||||
from html import escape as hescape
|
||||
try:
|
||||
from PyQt5 import QtCore
|
||||
except ImportError:
|
||||
QtCore = None
|
||||
from .shared import md5Checksum, getImageFileName, walkSort, walkLevel, sanitizeTrace, subprocess_run_silent
|
||||
|
||||
from .shared import md5Checksum, getImageFileName, walkSort, walkLevel, sanitizeTrace, subprocess_run
|
||||
from . import comic2panel
|
||||
from . import image
|
||||
from . import comicarchive
|
||||
@@ -54,6 +50,8 @@ from . import metadata
|
||||
from . import kindle
|
||||
from . import __version__
|
||||
|
||||
ImageFile.LOAD_TRUNCATED_IMAGES = True
|
||||
|
||||
|
||||
def main(argv=None):
|
||||
global options
|
||||
@@ -506,15 +504,18 @@ def buildEPUB(path, chapternames, tomenumber):
|
||||
chapter = False
|
||||
dirnames, filenames = walkSort(dirnames, filenames)
|
||||
for afile in filenames:
|
||||
if cover is None:
|
||||
cover = os.path.join(os.path.join(path, 'OEBPS', 'Images'),
|
||||
'cover' + getImageFileName(afile)[1])
|
||||
options.covers.append((image.Cover(os.path.join(dirpath, afile), cover, options,
|
||||
tomenumber), options.uuid))
|
||||
if options.dedupecover:
|
||||
os.remove(os.path.join(dirpath, afile))
|
||||
continue
|
||||
filelist.append(buildHTML(dirpath, afile, os.path.join(dirpath, afile)))
|
||||
if not chapter:
|
||||
chapterlist.append((dirpath.replace('Images', 'Text'), filelist[-1][1]))
|
||||
chapter = True
|
||||
if cover is None:
|
||||
cover = os.path.join(os.path.join(path, 'OEBPS', 'Images'),
|
||||
'cover' + getImageFileName(filelist[-1][1])[1])
|
||||
options.covers.append((image.Cover(os.path.join(filelist[-1][0], filelist[-1][1]), cover, options,
|
||||
tomenumber), options.uuid))
|
||||
# Overwrite chapternames if tree is flat and ComicInfo.xml has bookmarks
|
||||
if not chapternames and options.chapters:
|
||||
chapterlist = []
|
||||
@@ -646,6 +647,9 @@ def getWorkFolder(afile):
|
||||
try:
|
||||
cbx = comicarchive.ComicArchive(afile)
|
||||
path = cbx.extract(workdir)
|
||||
tdir = os.listdir(workdir)
|
||||
if 'ComicInfo.xml' in tdir:
|
||||
tdir.remove('ComicInfo.xml')
|
||||
except OSError as e:
|
||||
rmtree(workdir, True)
|
||||
raise UserWarning(e)
|
||||
@@ -691,7 +695,6 @@ def getOutputFilename(srcpath, wantedname, ext, tomenumber):
|
||||
|
||||
def getComicInfo(path, originalpath):
|
||||
xmlPath = os.path.join(path, 'ComicInfo.xml')
|
||||
options.authors = ['KCC']
|
||||
options.chapters = []
|
||||
options.summary = ''
|
||||
titleSuffix = ''
|
||||
@@ -703,13 +706,18 @@ def getComicInfo(path, originalpath):
|
||||
options.title = os.path.splitext(os.path.basename(originalpath))[0]
|
||||
else:
|
||||
defaultTitle = False
|
||||
if options.author == 'defaultauthor':
|
||||
defaultAuthor = True
|
||||
options.authors = ['KCC']
|
||||
else:
|
||||
defaultAuthor = False
|
||||
options.authors = [options.author]
|
||||
if os.path.exists(xmlPath):
|
||||
try:
|
||||
xml = metadata.MetadataParser(xmlPath)
|
||||
except Exception:
|
||||
os.remove(xmlPath)
|
||||
return
|
||||
options.authors = []
|
||||
if xml.data['Title']:
|
||||
options.title = hescape(xml.data['Title'])
|
||||
elif defaultTitle:
|
||||
@@ -720,14 +728,16 @@ def getComicInfo(path, originalpath):
|
||||
if xml.data['Number']:
|
||||
titleSuffix += ' #' + xml.data['Number'].zfill(3)
|
||||
options.title += titleSuffix
|
||||
for field in ['Writers', 'Pencillers', 'Inkers', 'Colorists']:
|
||||
for person in xml.data[field]:
|
||||
options.authors.append(hescape(person))
|
||||
if len(options.authors) > 0:
|
||||
options.authors = list(set(options.authors))
|
||||
options.authors.sort()
|
||||
else:
|
||||
options.authors = ['KCC']
|
||||
if defaultAuthor:
|
||||
options.authors = []
|
||||
for field in ['Writers', 'Pencillers', 'Inkers', 'Colorists']:
|
||||
for person in xml.data[field]:
|
||||
options.authors.append(hescape(person))
|
||||
if len(options.authors) > 0:
|
||||
options.authors = list(set(options.authors))
|
||||
options.authors.sort()
|
||||
else:
|
||||
options.authors = ['KCC']
|
||||
if xml.data['Bookmarks'] and options.batchsplit == 0:
|
||||
options.chapters = xml.data['Bookmarks']
|
||||
if xml.data['Summary']:
|
||||
@@ -896,7 +906,7 @@ def detectCorruption(tmppath, orgpath):
|
||||
GUI.addMessage.emit('Source files are probably created by KCC. The second conversion will decrease quality.'
|
||||
, 'warning', False)
|
||||
GUI.addMessage.emit('', '', False)
|
||||
if imageSmaller > imageNumber * 0.25 and not options.upscale and not options.stretch:
|
||||
if imageSmaller > imageNumber * 0.25 and not options.upscale and not options.stretch and options.profile != 'KS':
|
||||
print("WARNING: More than 25% of images are smaller than target device resolution. "
|
||||
"Consider enabling stretching or upscaling to improve readability.")
|
||||
if GUI:
|
||||
@@ -947,8 +957,8 @@ def makeParser():
|
||||
help="Full path to comic folder or file(s) to be processed.")
|
||||
|
||||
main_options.add_argument("-p", "--profile", action="store", dest="profile", default="KV",
|
||||
help="Device profile (Available options: K1, K2, K34, K578, KDX, KPW, KPW5, KV, KO, "
|
||||
"K11, KS, KoMT, KoG, KoGHD, KoA, KoAHD, KoAH2O, KoAO, KoN, KoC, KoL, KoF, KoS, KoE)"
|
||||
help="Device profile (Available options: K1, K2, K34, K578, KDX, KPW, KPW5, KPW6, KCS12, KV, KO, "
|
||||
"K11, KS, KoMT, KoG, KoGHD, KoA, KoAHD, KoAH2O, KoAO, KoN, KoC, KoCC, KoL, KoLC, KoF, KoS, KoE)"
|
||||
" [Default=KV]")
|
||||
main_options.add_argument("-m", "--manga-style", action="store_true", dest="righttoleft", default=False,
|
||||
help="Manga style (right-to-left reading and splitting)")
|
||||
@@ -966,12 +976,16 @@ def makeParser():
|
||||
help="Output generated file to specified directory or file")
|
||||
output_options.add_argument("-t", "--title", action="store", dest="title", default="defaulttitle",
|
||||
help="Comic title [Default=filename or directory name]")
|
||||
output_options.add_argument("-a", "--author", action="store", dest="author", default="defaultauthor",
|
||||
help="Author name [Default=KCC]")
|
||||
output_options.add_argument("-f", "--format", action="store", dest="format", default="Auto",
|
||||
help="Output format (Available options: Auto, MOBI, EPUB, CBZ, KFX, MOBI+EPUB) "
|
||||
"[Default=Auto]")
|
||||
output_options.add_argument("-b", "--batchsplit", type=int, dest="batchsplit", default="0",
|
||||
help="Split output into multiple files. 0: Don't split 1: Automatic mode "
|
||||
"2: Consider every subdirectory as separate volume [Default=0]")
|
||||
output_options.add_argument("--dedupecover", action="store_true", dest="dedupecover", default=False,
|
||||
help="De-duplicate the cover as the first page in the book")
|
||||
|
||||
processing_options.add_argument("-n", "--noprocessing", action="store_true", dest="noprocessing", default=False,
|
||||
help="Do not modify image and ignore any profil or processing option")
|
||||
@@ -1032,16 +1046,16 @@ def checkOptions(options):
|
||||
options.kfx = False
|
||||
options.supportSyntheticSpread = False
|
||||
if options.format == 'Auto':
|
||||
if options.profile in ['K1', 'K2', 'K34', 'K578', 'KPW', 'KPW5', 'KV', 'KO', 'K11', 'KS']:
|
||||
if options.profile in ['K1', 'K2', 'K34', 'K578', 'KPW', 'KPW5', 'KPW6', 'KCS12', 'KV', 'KO', 'K11', 'KS']:
|
||||
options.format = 'MOBI'
|
||||
elif options.profile in ['OTHER', 'KoMT', 'KoG', 'KoGHD', 'KoA', 'KoAHD', 'KoAH2O', 'KoAO',
|
||||
'KoN', 'KoC', 'KoL', 'KoF', 'KoS', 'KoE']:
|
||||
'KoN', 'KoC', 'KoCC', 'KoL', 'KoLC', 'KoF', 'KoS', 'KoE']:
|
||||
options.format = 'EPUB'
|
||||
elif options.profile in ['KDX']:
|
||||
options.format = 'CBZ'
|
||||
if options.profile in ['K1', 'K2', 'K34', 'K578', 'KPW', 'KPW5', 'KV', 'KO', 'K11', 'KS']:
|
||||
if options.profile in ['K1', 'K2', 'K34', 'K578', 'KPW', 'KPW5', 'KPW6', 'KCS12', 'KV', 'KO', 'K11', 'KS']:
|
||||
options.iskindle = True
|
||||
elif options.profile in ['OTHER', 'KoMT', 'KoG', 'KoGHD', 'KoA', 'KoAHD', 'KoAH2O', 'KoAO', 'KoN', 'KoC', 'KoL', 'KoF', 'KoS', 'KoE']:
|
||||
elif options.profile in ['OTHER', 'KoMT', 'KoG', 'KoGHD', 'KoA', 'KoAHD', 'KoAH2O', 'KoAO', 'KoN', 'KoC', 'KoCC', 'KoL', 'KoLC', 'KoF', 'KoS', 'KoE']:
|
||||
options.isKobo = True
|
||||
# Other Kobo devices probably support synthetic spreads as well, but
|
||||
# they haven't been tested.
|
||||
@@ -1092,10 +1106,6 @@ def checkOptions(options):
|
||||
image.ProfileData.Profiles["Custom"] = newProfile
|
||||
options.profile = "Custom"
|
||||
options.profileData = image.ProfileData.Profiles[options.profile]
|
||||
# kindle scribe conversion to mobi is limited in resolution by kindlegen, same with send to kindle and epub
|
||||
if options.profile == 'KS' and (options.format == 'MOBI' or options.format == 'EPUB'):
|
||||
options.profileData = list(options.profileData)
|
||||
options.profileData[1] = (1440, 1920)
|
||||
return options
|
||||
|
||||
|
||||
@@ -1104,13 +1114,13 @@ def checkTools(source):
|
||||
if source.endswith('.CB7') or source.endswith('.7Z') or source.endswith('.RAR') or source.endswith('.CBR') or \
|
||||
source.endswith('.ZIP') or source.endswith('.CBZ'):
|
||||
try:
|
||||
subprocess_run_silent(['7z'], stdout=PIPE, stderr=STDOUT)
|
||||
subprocess_run(['7z'], stdout=PIPE, stderr=STDOUT)
|
||||
except FileNotFoundError:
|
||||
print('ERROR: 7z is missing!')
|
||||
sys.exit(1)
|
||||
if options.format == 'MOBI':
|
||||
try:
|
||||
subprocess_run_silent(['kindlegen', '-locale', 'en'], stdout=PIPE, stderr=STDOUT)
|
||||
subprocess_run(['kindlegen', '-locale', 'en'], stdout=PIPE, stderr=STDOUT)
|
||||
except FileNotFoundError:
|
||||
print('ERROR: KindleGen is missing!')
|
||||
sys.exit(1)
|
||||
@@ -1267,7 +1277,7 @@ def makeMOBIWorker(item):
|
||||
kindlegenError = ''
|
||||
try:
|
||||
if os.path.getsize(item) < 629145600:
|
||||
output = subprocess_run_silent(['kindlegen', '-dont_append_source', '-locale', 'en', item],
|
||||
output = subprocess_run(['kindlegen', '-dont_append_source', '-locale', 'en', item],
|
||||
stdout=PIPE, stderr=STDOUT, encoding='UTF-8')
|
||||
for line in output.stdout.splitlines():
|
||||
# ERROR: Generic error
|
||||
|
||||
@@ -25,10 +25,6 @@ from shutil import rmtree, copytree, move
|
||||
from multiprocessing import Pool
|
||||
from PIL import Image, ImageChops, ImageOps, ImageDraw
|
||||
from .shared import getImageFileName, walkLevel, walkSort, sanitizeTrace
|
||||
try:
|
||||
from PyQt5 import QtCore
|
||||
except ImportError:
|
||||
QtCore = None
|
||||
|
||||
|
||||
def mergeDirectoryTick(output):
|
||||
|
||||
@@ -18,15 +18,14 @@
|
||||
# PERFORMANCE OF THIS SOFTWARE.
|
||||
#
|
||||
|
||||
from functools import cached_property
|
||||
import os
|
||||
import platform
|
||||
import subprocess
|
||||
import distro
|
||||
from shutil import move
|
||||
from subprocess import STDOUT, PIPE
|
||||
from subprocess import STDOUT, PIPE, CalledProcessError
|
||||
from xml.dom.minidom import parseString
|
||||
from xml.parsers.expat import ExpatError
|
||||
from .shared import subprocess_run_silent
|
||||
from .shared import subprocess_run
|
||||
|
||||
EXTRACTION_ERROR = 'Failed to extract archive. Try extracting file outside of KCC.'
|
||||
|
||||
@@ -34,53 +33,78 @@ EXTRACTION_ERROR = 'Failed to extract archive. Try extracting file outside of KC
|
||||
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 = subprocess_run_silent(['7z', 'l', '-y', '-p1', self.filepath], stderr=STDOUT, stdout=PIPE)
|
||||
for line in process.stdout.splitlines():
|
||||
if b'Type =' in line:
|
||||
self.type = line.rstrip().decode().split(' = ')[1].upper()
|
||||
break
|
||||
if process.returncode != 0 and distro.id() == 'fedora':
|
||||
process = subprocess_run_silent(['unrar', 'l', '-y', '-p1', self.filepath], stderr=STDOUT, stdout=PIPE)
|
||||
for line in process.stdout.splitlines():
|
||||
if b'Details: ' in line:
|
||||
self.type = line.rstrip().decode().split(' ')[1].upper()
|
||||
break
|
||||
if process.returncode != 0:
|
||||
raise OSError(EXTRACTION_ERROR)
|
||||
|
||||
@cached_property
|
||||
def type(self):
|
||||
extraction_commands = [
|
||||
['7z', 'l', '-y', '-p1', self.filepath],
|
||||
]
|
||||
|
||||
if distro.id() == 'fedora':
|
||||
extraction_commands.append(
|
||||
['unrar', 'l', '-y', '-p1', self.filepath],
|
||||
)
|
||||
|
||||
for cmd in extraction_commands:
|
||||
try:
|
||||
process = subprocess_run(cmd, capture_output=True, check=True)
|
||||
for line in process.stdout.splitlines():
|
||||
if b'Type =' in line:
|
||||
return line.rstrip().decode().split(' = ')[1].upper()
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
except CalledProcessError:
|
||||
pass
|
||||
|
||||
raise OSError(EXTRACTION_ERROR)
|
||||
|
||||
def extract(self, targetdir):
|
||||
if not os.path.isdir(targetdir):
|
||||
raise OSError('Target directory doesn\'t exist.')
|
||||
process = subprocess_run_silent(['7z', 'x', '-y', '-xr!__MACOSX', '-xr!.DS_Store', '-xr!thumbs.db', '-xr!Thumbs.db', '-o' + targetdir, self.filepath],
|
||||
stdout=PIPE, stderr=STDOUT)
|
||||
if process.returncode != 0 and distro.id() == 'fedora':
|
||||
process = subprocess_run_silent(['unrar', 'x', '-y', '-x__MACOSX', '-x.DS_Store', '-xthumbs.db', '-xThumbs.db', self.filepath, targetdir]
|
||||
, stdout=PIPE, stderr=STDOUT)
|
||||
if process.returncode != 0:
|
||||
raise OSError(EXTRACTION_ERROR)
|
||||
elif process.returncode != 0 and platform.system() == 'Darwin':
|
||||
process = subprocess_run_silent(['unar', self.filepath, '-f', '-o', targetdir],
|
||||
stdout=PIPE, stderr=STDOUT)
|
||||
elif process.returncode != 0:
|
||||
|
||||
missing = []
|
||||
|
||||
extraction_commands = [
|
||||
['tar', '--exclude', '__MACOSX', '--exclude', '.DS_Store', '--exclude', 'thumbs.db', '--exclude', 'Thumbs.db', '-xf', self.filepath, '-C', targetdir],
|
||||
['7z', 'x', '-y', '-xr!__MACOSX', '-xr!.DS_Store', '-xr!thumbs.db', '-xr!Thumbs.db', '-o' + targetdir, self.filepath],
|
||||
]
|
||||
|
||||
if platform.system() == 'Darwin':
|
||||
extraction_commands.append(
|
||||
['unar', self.filepath, '-f', '-o', targetdir]
|
||||
)
|
||||
|
||||
if distro.id() == 'fedora':
|
||||
extraction_commands.append(
|
||||
['unrar', 'x', '-y', '-x__MACOSX', '-x.DS_Store', '-xthumbs.db', '-xThumbs.db', self.filepath, targetdir]
|
||||
)
|
||||
|
||||
for cmd in extraction_commands:
|
||||
try:
|
||||
subprocess_run(cmd, capture_output=True, check=True)
|
||||
return targetdir
|
||||
except FileNotFoundError:
|
||||
missing.append(cmd[0])
|
||||
except CalledProcessError:
|
||||
pass
|
||||
|
||||
if missing:
|
||||
raise OSError(f'Extraction failed, install <a href="https://github.com/ciromattia/kcc#7-zip">specialized extraction software.</a> ')
|
||||
else:
|
||||
raise OSError(EXTRACTION_ERROR)
|
||||
tdir = os.listdir(targetdir)
|
||||
if 'ComicInfo.xml' in tdir:
|
||||
tdir.remove('ComicInfo.xml')
|
||||
return targetdir
|
||||
|
||||
def addFile(self, sourcefile):
|
||||
if self.type in ['RAR', 'RAR5']:
|
||||
raise NotImplementedError
|
||||
process = subprocess_run_silent(['7z', 'a', '-y', self.filepath, sourcefile],
|
||||
process = subprocess_run(['7z', 'a', '-y', self.filepath, sourcefile],
|
||||
stdout=PIPE, stderr=STDOUT)
|
||||
if process.returncode != 0:
|
||||
raise OSError('Failed to add the file.')
|
||||
|
||||
def extractMetadata(self):
|
||||
process = subprocess_run_silent(['7z', 'x', '-y', '-so', self.filepath, 'ComicInfo.xml'],
|
||||
process = subprocess_run(['7z', 'x', '-y', '-so', self.filepath, 'ComicInfo.xml'],
|
||||
stdout=PIPE, stderr=STDOUT)
|
||||
if process.returncode != 0:
|
||||
raise OSError(EXTRACTION_ERROR)
|
||||
|
||||
@@ -80,7 +80,7 @@ class ProfileData:
|
||||
|
||||
Profiles = {
|
||||
'K1': ("Kindle 1", (600, 670), Palette4, 1.8),
|
||||
'K11': ("Kindle 11", (1072, 1448), Palette16, 1.8),
|
||||
'K11': ("Kindle 11/12", (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),
|
||||
@@ -88,6 +88,8 @@ class ProfileData:
|
||||
'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),
|
||||
'KPW6': ("Kindle Paperwhite 6", (1264, 1680), Palette16, 1.8),
|
||||
'KCS12': ("Kindle Colorsoft", (1264, 1680), 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),
|
||||
@@ -99,7 +101,9 @@ class ProfileData:
|
||||
'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),
|
||||
'KoCC': ("Kobo Clara Colour", (1072, 1448), Palette16, 1.8),
|
||||
'KoL': ("Kobo Libra H2O/Kobo Libra 2", (1264, 1680), Palette16, 1.8),
|
||||
'KoLC': ("Kobo Libra Colour", (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),
|
||||
@@ -239,6 +243,7 @@ class ComicPage:
|
||||
_, self.size, self.palette, self.gamma = self.opt.profileData
|
||||
if self.opt.hq:
|
||||
self.size = (int(self.size[0] * 1.5), int(self.size[1] * 1.5))
|
||||
self.kindle_scribe_azw3 = (options.profile == 'KS') and (options.format in ('MOBI', 'EPUB'))
|
||||
self.image = image
|
||||
self.color = color
|
||||
self.fill = fill
|
||||
@@ -308,6 +313,9 @@ class ComicPage:
|
||||
self.image = self.image.quantize(palette=palImg)
|
||||
|
||||
def resizeImage(self):
|
||||
# kindle scribe conversion to mobi is limited in resolution by kindlegen, same with send to kindle and epub
|
||||
if self.kindle_scribe_azw3:
|
||||
self.size = (1440, 1920)
|
||||
ratio_device = float(self.size[1]) / float(self.size[0])
|
||||
ratio_image = float(self.image.size[1]) / float(self.image.size[0])
|
||||
method = self.resize_method()
|
||||
@@ -326,14 +334,15 @@ class ComicPage:
|
||||
elif self.opt.format == 'CBZ' or self.opt.kfx:
|
||||
self.image = ImageOps.pad(self.image, self.size, method=method, color=self.fill)
|
||||
else:
|
||||
if self.kindle_scribe_azw3:
|
||||
self.size = (1860, 1920)
|
||||
self.image = ImageOps.contain(self.image, self.size, method=method)
|
||||
|
||||
def resize_method(self):
|
||||
if self.image.size[0] <= self.size[0] and self.image.size[1] <= self.size[1]:
|
||||
method = Image.Resampling.BICUBIC
|
||||
return Image.Resampling.BICUBIC
|
||||
else:
|
||||
method = Image.Resampling.LANCZOS
|
||||
return method
|
||||
return Image.Resampling.LANCZOS
|
||||
|
||||
def getBoundingBox(self, tmptmg):
|
||||
min_margin = [int(0.005 * i + 0.5) for i in tmptmg.size]
|
||||
|
||||
@@ -31,7 +31,7 @@ class Kindle:
|
||||
def findDevice(self):
|
||||
for drive in reversed(psutil.disk_partitions(False)):
|
||||
if (drive[2] == 'FAT32' and drive[3] == 'rw,removable') or \
|
||||
(drive[2] in ('vfat', 'msdos', 'FAT') and 'rw' in drive[3]):
|
||||
(drive[2] in ('vfat', 'msdos', 'FAT', 'apfs') and 'rw' in drive[3]):
|
||||
if os.path.isdir(os.path.join(drive[1], 'system')) and \
|
||||
os.path.isdir(os.path.join(drive[1], 'documents')):
|
||||
return drive[1]
|
||||
|
||||
@@ -22,7 +22,7 @@ import os
|
||||
from hashlib import md5
|
||||
from html.parser import HTMLParser
|
||||
import subprocess
|
||||
from distutils.version import StrictVersion
|
||||
from packaging.version import Version
|
||||
from re import split
|
||||
import sys
|
||||
from traceback import format_tb
|
||||
@@ -102,11 +102,11 @@ def dependencyCheck(level):
|
||||
missing = []
|
||||
if level > 2:
|
||||
try:
|
||||
from PyQt5.QtCore import qVersion as qtVersion
|
||||
if StrictVersion('5.6.0') > StrictVersion(qtVersion()):
|
||||
missing.append('PyQt 5.6.0+')
|
||||
from PySide6.QtCore import qVersion as qtVersion
|
||||
if Version('6.5.1') > Version(qtVersion()):
|
||||
missing.append('PySide 6.5.1+')
|
||||
except ImportError:
|
||||
missing.append('PyQt 5.6.0+')
|
||||
missing.append('PySide 6.5.1+')
|
||||
try:
|
||||
import raven
|
||||
except ImportError:
|
||||
@@ -114,7 +114,7 @@ def dependencyCheck(level):
|
||||
if level > 1:
|
||||
try:
|
||||
from psutil import __version__ as psutilVersion
|
||||
if StrictVersion('5.0.0') > StrictVersion(psutilVersion):
|
||||
if Version('5.0.0') > Version(psutilVersion):
|
||||
missing.append('psutil 5.0.0+')
|
||||
except ImportError:
|
||||
missing.append('psutil 5.0.0+')
|
||||
@@ -123,13 +123,13 @@ def dependencyCheck(level):
|
||||
from slugify import __version__ as slugifyVersion
|
||||
if isinstance(slugifyVersion, ModuleType):
|
||||
slugifyVersion = slugifyVersion.__version__
|
||||
if StrictVersion('1.2.1') > StrictVersion(slugifyVersion):
|
||||
if Version('1.2.1') > Version(slugifyVersion):
|
||||
missing.append('python-slugify 1.2.1+')
|
||||
except ImportError:
|
||||
missing.append('python-slugify 1.2.1+')
|
||||
try:
|
||||
from PIL import __version__ as pillowVersion
|
||||
if StrictVersion('5.2.0') > StrictVersion(pillowVersion):
|
||||
if Version('5.2.0') > Version(pillowVersion):
|
||||
missing.append('Pillow 5.2.0+')
|
||||
except ImportError:
|
||||
missing.append('Pillow 5.2.0+')
|
||||
@@ -137,7 +137,7 @@ def dependencyCheck(level):
|
||||
print('ERROR: ' + ', '.join(missing) + ' is not installed!')
|
||||
sys.exit(1)
|
||||
|
||||
def subprocess_run_silent(command, **kwargs):
|
||||
def subprocess_run(command, **kwargs):
|
||||
if (os.name == 'nt'):
|
||||
kwargs.setdefault('creationflags', subprocess.CREATE_NO_WINDOW)
|
||||
return subprocess.run(command, **kwargs)
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
PyQt5>=5.6.0
|
||||
PySide6>=6.5.1
|
||||
Pillow>=5.2.0
|
||||
psutil>=5.0.0
|
||||
psutil>=5.9.5
|
||||
requests>=2.31.0
|
||||
python-slugify>=1.2.1
|
||||
raven>=6.0.0
|
||||
# PyQt5-tools
|
||||
packaging>=23.2
|
||||
mozjpeg-lossless-optimization>=1.1.2
|
||||
natsort[fast]>=8.4.0
|
||||
distro
|
||||
distro>=1.8.0
|
||||
|
||||
17
setup.py
17
setup.py
@@ -11,10 +11,9 @@ Create EXE/APP:
|
||||
"""
|
||||
|
||||
import os
|
||||
import platform
|
||||
import sys
|
||||
import shutil
|
||||
import setuptools
|
||||
import distutils.cmd
|
||||
from kindlecomicconverter import __version__
|
||||
|
||||
NAME = 'KindleComicConverter'
|
||||
@@ -23,7 +22,7 @@ VERSION = __version__
|
||||
|
||||
|
||||
# noinspection PyUnresolvedReferences
|
||||
class BuildBinaryCommand(distutils.cmd.Command):
|
||||
class BuildBinaryCommand(setuptools.Command):
|
||||
description = 'build binary release'
|
||||
user_options = []
|
||||
|
||||
@@ -37,16 +36,16 @@ class BuildBinaryCommand(distutils.cmd.Command):
|
||||
def run(self):
|
||||
VERSION = __version__
|
||||
if sys.platform == 'darwin':
|
||||
os.system('pyinstaller -y -D -i icons/comic2ebook.icns -n "Kindle Comic Converter" -w -s kcc.py')
|
||||
os.system('pyinstaller --hidden-import=_cffi_backend -y -D -i icons/comic2ebook.icns -n "Kindle Comic Converter" -w -s kcc.py')
|
||||
# TODO /usr/bin/codesign --force -s "$MACOS_CERTIFICATE_NAME" --options runtime dist/Applications/Kindle\ Comic\ Converter.app -v
|
||||
os.system('appdmg kcc.json dist/KindleComicConverter_osx_' + VERSION + '.dmg')
|
||||
os.system(f'appdmg kcc.json dist/kcc_macos_{platform.processor()}_{VERSION}.dmg')
|
||||
sys.exit(0)
|
||||
elif sys.platform == 'win32':
|
||||
os.system('pyinstaller -y -F -i icons\\comic2ebook.ico -n KCC_' + VERSION + ' -w --noupx kcc.py')
|
||||
os.system('pyinstaller --hidden-import=_cffi_backend -y -F -i icons\\comic2ebook.ico -n KCC_' + VERSION + ' -w --noupx kcc.py')
|
||||
sys.exit(0)
|
||||
elif sys.platform == 'linux':
|
||||
os.system(
|
||||
'pyinstaller --hidden-import=queue -y -F -i icons/comic2ebook.ico -n kcc_linux_' + VERSION + ' kcc.py')
|
||||
'pyinstaller --hidden-import=_cffi_backend --hidden-import=queue -y -F -i icons/comic2ebook.ico -n kcc_linux_' + VERSION + ' kcc.py')
|
||||
sys.exit(0)
|
||||
else:
|
||||
sys.exit(0)
|
||||
@@ -75,9 +74,9 @@ setuptools.setup(
|
||||
},
|
||||
packages=['kindlecomicconverter'],
|
||||
install_requires=[
|
||||
'PyQt5>=5.6.0',
|
||||
'pyside6>=6.5.1',
|
||||
'Pillow>=5.2.0',
|
||||
'psutil>=5.0.0',
|
||||
'psutil>=5.9.5',
|
||||
'python-slugify>=1.2.1,<9.0.0',
|
||||
'raven>=6.0.0',
|
||||
'requests>=2.31.0',
|
||||
|
||||
Reference in New Issue
Block a user