mirror of
https://github.com/ciromattia/kcc
synced 2026-04-17 22:48:53 +00:00
Compare commits
39 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b2aaa9e8b0 | ||
|
|
e8502f008a | ||
|
|
169a41e7d2 | ||
|
|
57cf669cdd | ||
|
|
0b4f089b8e | ||
|
|
7eb985337c | ||
|
|
d62690e8bf | ||
|
|
3988f2012f | ||
|
|
6cdd9d5909 | ||
|
|
c29a4beac9 | ||
|
|
5f7bdef325 | ||
|
|
54b5d698ee | ||
|
|
a99c63acea | ||
|
|
251df2e7ba | ||
|
|
b1379b7c59 | ||
|
|
983bde1691 | ||
|
|
e79e5a311c | ||
|
|
39c73dbc0f | ||
|
|
915c9389ef | ||
|
|
89d887710e | ||
|
|
2e9bc5381a | ||
|
|
ab1ce158c7 | ||
|
|
6278adfb25 | ||
|
|
6e6c13047e | ||
|
|
b528dab711 | ||
|
|
2ffefee928 | ||
|
|
a5e5407363 | ||
|
|
da1ba64bd2 | ||
|
|
6dcaf9a6d1 | ||
|
|
3090a47f20 | ||
|
|
1e537915d4 | ||
|
|
7273ca25b8 | ||
|
|
68da853e42 | ||
|
|
431862a2e9 | ||
|
|
65062f8984 | ||
|
|
8122fa1e45 | ||
|
|
13fedff77b | ||
|
|
61b1207a3e | ||
|
|
60e9f075b8 |
31
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
31
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
---
|
||||||
|
name: Bug report
|
||||||
|
about: Create a report to help us improve
|
||||||
|
title: ''
|
||||||
|
labels: ''
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Describe the bug**
|
||||||
|
A clear and concise description of what the bug is.
|
||||||
|
|
||||||
|
**To Reproduce**
|
||||||
|
Steps to reproduce the behavior:
|
||||||
|
1. Go to '...'
|
||||||
|
2. Click on '....'
|
||||||
|
3. Scroll down to '....'
|
||||||
|
4. See error
|
||||||
|
|
||||||
|
**Expected behavior**
|
||||||
|
A clear and concise description of what you expected to happen.
|
||||||
|
|
||||||
|
**Screenshots**
|
||||||
|
Add a screenshot of your KCC settings.
|
||||||
|
|
||||||
|
**Desktop (please complete the following information):**
|
||||||
|
- OS: [e.g. macOS, Linux, Windows 11]
|
||||||
|
- Device [e.g. Kindle Paperwhite 3rd gen, Kobo Libra 2]
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
Add any other context about the problem here.
|
||||||
8
.github/workflows/codeql-analysis.yml
vendored
8
.github/workflows/codeql-analysis.yml
vendored
@@ -38,11 +38,11 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
# Initializes the CodeQL tools for scanning.
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@v2
|
uses: github/codeql-action/init@v3
|
||||||
with:
|
with:
|
||||||
languages: ${{ matrix.language }}
|
languages: ${{ matrix.language }}
|
||||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||||
@@ -56,7 +56,7 @@ jobs:
|
|||||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||||
# If this step fails, then you should remove it and run the build manually (see below)
|
# If this step fails, then you should remove it and run the build manually (see below)
|
||||||
- name: Autobuild
|
- name: Autobuild
|
||||||
uses: github/codeql-action/autobuild@v2
|
uses: github/codeql-action/autobuild@v3
|
||||||
|
|
||||||
# ℹ️ Command-line programs to run using the OS shell.
|
# ℹ️ Command-line programs to run using the OS shell.
|
||||||
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||||
@@ -69,6 +69,6 @@ jobs:
|
|||||||
# ./location_of_script_within_repo/buildscript.sh
|
# ./location_of_script_within_repo/buildscript.sh
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@v2
|
uses: github/codeql-action/analyze@v3
|
||||||
with:
|
with:
|
||||||
category: "/language:${{matrix.language}}"
|
category: "/language:${{matrix.language}}"
|
||||||
|
|||||||
6
.github/workflows/package-linux.yml
vendored
6
.github/workflows/package-linux.yml
vendored
@@ -25,9 +25,9 @@ jobs:
|
|||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: 3.11
|
python-version: 3.11
|
||||||
cache: 'pip'
|
cache: 'pip'
|
||||||
@@ -59,7 +59,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
UPDATE_INFO: gh-releases-zsync|ciromattia|kcc|latest|*x86_64.AppImage.zsync
|
UPDATE_INFO: gh-releases-zsync|ciromattia|kcc|latest|*x86_64.AppImage.zsync
|
||||||
- name: upload artifact
|
- name: upload artifact
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: AppImage
|
name: AppImage
|
||||||
path: './*.AppImage*'
|
path: './*.AppImage*'
|
||||||
|
|||||||
8
.github/workflows/package-macos.yml
vendored
8
.github/workflows/package-macos.yml
vendored
@@ -25,9 +25,9 @@ jobs:
|
|||||||
build:
|
build:
|
||||||
runs-on: macos-latest
|
runs-on: macos-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: 3.11
|
python-version: 3.11
|
||||||
cache: 'pip'
|
cache: 'pip'
|
||||||
@@ -66,7 +66,7 @@ jobs:
|
|||||||
# apply provisioning profile
|
# apply provisioning profile
|
||||||
mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
|
mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
|
||||||
cp $PP_PATH ~/Library/MobileDevice/Provisioning\ Profiles
|
cp $PP_PATH ~/Library/MobileDevice/Provisioning\ Profiles
|
||||||
- uses: actions/setup-node@v3
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 16
|
node-version: 16
|
||||||
- run: npm install -g appdmg
|
- run: npm install -g appdmg
|
||||||
@@ -75,7 +75,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
python setup.py build_binary
|
python setup.py build_binary
|
||||||
- name: upload build
|
- name: upload build
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: mac-os-build
|
name: mac-os-build
|
||||||
path: dist/*.dmg
|
path: dist/*.dmg
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ jobs:
|
|||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
# - name: Set up Python
|
# - name: Set up Python
|
||||||
# uses: actions/setup-python@v4
|
# uses: actions/setup-python@v4
|
||||||
# with:
|
# with:
|
||||||
@@ -44,10 +44,10 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
version_built=$(cat kindlecomicconverter/__init__.py | grep version | awk '{print $3}' | sed "s/[^.0-9b]//g")
|
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.exe dist/windows/kcc_${version_built}.exe
|
||||||
mv dist/windows/kcc-c2e.exe dist/windows/kcc-c2e_${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-c2p.exe dist/windows/kcc_c2p_${version_built}.exe
|
||||||
- name: upload build
|
- name: upload build
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: windows-build
|
name: windows-build
|
||||||
path: dist/windows/*.exe
|
path: dist/windows/*.exe
|
||||||
@@ -60,4 +60,4 @@ jobs:
|
|||||||
files: |
|
files: |
|
||||||
CHANGELOG.md
|
CHANGELOG.md
|
||||||
LICENSE.txt
|
LICENSE.txt
|
||||||
dist/windows/*.exe
|
dist/windows/*.exe
|
||||||
|
|||||||
10
.github/workflows/package-windows.yml
vendored
10
.github/workflows/package-windows.yml
vendored
@@ -25,11 +25,11 @@ jobs:
|
|||||||
build:
|
build:
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: 3.11
|
python-version: 3.8
|
||||||
cache: 'pip'
|
cache: 'pip'
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
env:
|
env:
|
||||||
@@ -42,7 +42,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
python setup.py build_binary
|
python setup.py build_binary
|
||||||
- name: upload build
|
- name: upload build
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: windows-build
|
name: windows-build
|
||||||
path: dist/*.exe
|
path: dist/*.exe
|
||||||
@@ -55,4 +55,4 @@ jobs:
|
|||||||
files: |
|
files: |
|
||||||
CHANGELOG.md
|
CHANGELOG.md
|
||||||
LICENSE.txt
|
LICENSE.txt
|
||||||
dist/*.exe
|
dist/*.exe
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -11,3 +11,4 @@ KindleComicConverter*.egg-info/
|
|||||||
/venv/
|
/venv/
|
||||||
/kindlegen*
|
/kindlegen*
|
||||||
/kcc.bat
|
/kcc.bat
|
||||||
|
.DS_Store
|
||||||
|
|||||||
63
README.md
63
README.md
@@ -28,11 +28,11 @@ If you find **KCC** valuable you can consider donating to the authors:
|
|||||||
- Paweł Jastrzębski:
|
- Paweł Jastrzębski:
|
||||||
- [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=YTTJ4LK2JDHPS)
|
- [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=YTTJ4LK2JDHPS)
|
||||||
- [](https://jastrzeb.ski/donate/)
|
- [](https://jastrzeb.ski/donate/)
|
||||||
|
- Alex Xu
|
||||||
|
- [](https://www.paypal.com/donate/?business=QFJVE7A6LCP6U&no_recurring=0&item_name=Kindle+Comic+Converter¤cy_code=USD)
|
||||||
|
|
||||||
|
|
||||||
## INSTALLATION
|
## DOWNLOADS
|
||||||
|
|
||||||
### DOWNLOADS
|
|
||||||
|
|
||||||
- **https://github.com/ciromattia/kcc/releases**
|
- **https://github.com/ciromattia/kcc/releases**
|
||||||
|
|
||||||
@@ -42,45 +42,41 @@ You probably want either
|
|||||||
- `kcc_*.*.*.exe` (Windows)
|
- `kcc_*.*.*.exe` (Windows)
|
||||||
- `KindleComicConverter_osx_*.*.*.dmg` (Mac)
|
- `KindleComicConverter_osx_*.*.*.dmg` (Mac)
|
||||||
|
|
||||||
Installation Wiki: https://github.com/ciromattia/kcc/wiki/Installation
|
The `c2e` and `c2p` versions are command line tools for power users.
|
||||||
|
|
||||||
- flatpak : https://flathub.org/apps/details/io.github.ciromattia.kcc
|
On Windows 11, you may need to run in compatibility mode for an older Windows version.
|
||||||
- Docker: https://github.com/ciromattia/kcc/pkgs/container/kcc
|
|
||||||
|
|
||||||
### DEPENDENCIES
|
On Mac, right click open to get past the security warning.
|
||||||
Following software is required to run Linux version of **KCC** and/or bare sources:
|
|
||||||
- Python 3.3+
|
|
||||||
- [PyQt5](https://pypi.python.org/pypi/PyQt5) 5.6.0+ (only needed for GUI)
|
|
||||||
- [Pillow](https://pypi.python.org/pypi/Pillow/) 4.0.0+ (5.2.0+ needed for WebP support)
|
|
||||||
- [psutil](https://pypi.python.org/pypi/psutil) 5.0.0+
|
|
||||||
- [python-slugify](https://pypi.python.org/pypi/python-slugify) 1.2.1+, <8.0.0
|
|
||||||
- [raven](https://pypi.python.org/pypi/raven) 6.0.0+ (only needed for GUI)
|
|
||||||
|
|
||||||
On Debian based distributions these two commands should install all needed dependencies:
|
For flatpak, Docker, and AppImage versions, refer to the wiki: https://github.com/ciromattia/kcc/wiki/Installation
|
||||||
|
|
||||||
|
## PREREQUISITES
|
||||||
|
|
||||||
|
You'll need to install various tools to access important but optional features.
|
||||||
|
|
||||||
```bash
|
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.
|
||||||
$ sudo apt-get install -y python3 python3-dev libpng-dev libjpeg-dev p7zip-full p7zip-rar unrar-free libgl1 python3-pyqt5 && \
|
|
||||||
python -m pip install --upgrade pip && \
|
### 7-Zip
|
||||||
python -m pip install --upgrade -r requirements.txt
|
|
||||||
|
#### 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
|
||||||
#### Optional dependencies
|
with [Homebrew](https://brew.sh/) installed
|
||||||
- Qt platform integration plugin for Deepin Desktop Environment
|
```
|
||||||
```bash
|
brew install p7zip
|
||||||
$ sudo apt-get install qt5dxcb-plugin
|
brew install unar
|
||||||
```
|
```
|
||||||
|
|
||||||
- KindleGen ~~[(deprecated link)](http://www.amazon.com/gp/feature.html?ie=UTF8&docId=1000765211)~~ v2.9+ (For MOBI generation)
|
### KindleGen
|
||||||
- should be placed in a directory reachable by your _PATH_ or in _KCC_ directory
|
|
||||||
- `KindleGen` can be found in [Kindle Previewer](https://www.amazon.com/Kindle-Previewer/b?ie=UTF8&node=21381691011)
|
|
||||||
- `KindleGen` can be also be found in [Kindle Comic Creator](https://www.amazon.com/b?node=23496309011)
|
|
||||||
- [7z](http://www.7-zip.org/download.html) *(For CBZ/ZIP, CBR/RAR, 7z/CB7 support)*
|
|
||||||
- Unrar (no rar in 7z on Fedora)
|
|
||||||
|
|
||||||
|
#### Windows / macOS KindleGen
|
||||||
|
|
||||||
|
Install [Kindle Previewer 3 (KP3)](https://www.amazon.com/Kindle-Previewer/b?ie=UTF8&node=21381691011). KCC will automatically detect KindleGen from it.
|
||||||
|
|
||||||
## INPUT FORMATS
|
## INPUT FORMATS
|
||||||
**KCC** can understand and convert, at the moment, the following input types:
|
**KCC** can understand and convert, at the moment, the following input types:
|
||||||
@@ -215,7 +211,12 @@ OTHER:
|
|||||||
```
|
```
|
||||||
|
|
||||||
## CREDITS
|
## CREDITS
|
||||||
**KCC** is made by [Ciro Mattia Gonano](http://github.com/ciromattia), [Paweł Jastrzębski](http://github.com/AcidWeb) and [Darodi](http://github.com/darodi) .
|
**KCC** is made by
|
||||||
|
|
||||||
|
- [Ciro Mattia Gonano](http://github.com/ciromattia)
|
||||||
|
- [Paweł Jastrzębski](http://github.com/AcidWeb)
|
||||||
|
- [Darodi](http://github.com/darodi)
|
||||||
|
- [Alex Xu](http://github.com/axu2)
|
||||||
|
|
||||||
This script born as a cross-platform alternative to `KindleComicParser` by **Dc5e** (published [here](http://www.mobileread.com/forums/showthread.php?t=192783)).
|
This script born as a cross-platform alternative to `KindleComicParser` by **Dc5e** (published [here](http://www.mobileread.com/forums/showthread.php?t=192783)).
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ dependencies:
|
|||||||
- python-slugify>=1.2.1
|
- python-slugify>=1.2.1
|
||||||
- raven>=6.0.0
|
- raven>=6.0.0
|
||||||
- distro
|
- distro
|
||||||
|
- natsort[fast]>=8.4.0
|
||||||
- pip
|
- pip
|
||||||
- pip:
|
- pip:
|
||||||
- mozjpeg-lossless-optimization>=1.1.2
|
- mozjpeg-lossless-optimization>=1.1.2
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import sys
|
|||||||
|
|
||||||
if sys.version_info < (3, 8, 0):
|
if sys.version_info < (3, 8, 0):
|
||||||
print('ERROR: This is a Python 3.8+ script!')
|
print('ERROR: This is a Python 3.8+ script!')
|
||||||
exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
from multiprocessing import freeze_support, set_start_method
|
from multiprocessing import freeze_support, set_start_method
|
||||||
from kindlecomicconverter.startup import startC2E
|
from kindlecomicconverter.startup import startC2E
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import sys
|
|||||||
|
|
||||||
if sys.version_info < (3, 8, 0):
|
if sys.version_info < (3, 8, 0):
|
||||||
print('ERROR: This is a Python 3.8+ script!')
|
print('ERROR: This is a Python 3.8+ script!')
|
||||||
exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
from multiprocessing import freeze_support, set_start_method
|
from multiprocessing import freeze_support, set_start_method
|
||||||
from kindlecomicconverter.startup import startC2P
|
from kindlecomicconverter.startup import startC2P
|
||||||
|
|||||||
2
kcc.py
2
kcc.py
@@ -22,7 +22,7 @@ import sys
|
|||||||
|
|
||||||
if sys.version_info < (3, 8, 0):
|
if sys.version_info < (3, 8, 0):
|
||||||
print('ERROR: This is a Python 3.8+ script!')
|
print('ERROR: This is a Python 3.8+ script!')
|
||||||
exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
# OS specific workarounds
|
# OS specific workarounds
|
||||||
import os
|
import os
|
||||||
|
|||||||
@@ -16,25 +16,25 @@
|
|||||||
# OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
# OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||||
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
# PERFORMANCE OF THIS SOFTWARE.
|
# PERFORMANCE OF THIS SOFTWARE.
|
||||||
import json
|
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
from urllib.parse import unquote
|
from urllib.parse import unquote
|
||||||
from urllib.request import urlretrieve, urlopen
|
|
||||||
from time import sleep
|
from time import sleep
|
||||||
from shutil import move, rmtree
|
from shutil import move, rmtree
|
||||||
from subprocess import STDOUT, PIPE
|
from subprocess import STDOUT, PIPE
|
||||||
|
|
||||||
|
import requests
|
||||||
# noinspection PyUnresolvedReferences
|
# noinspection PyUnresolvedReferences
|
||||||
from PyQt5 import QtGui, QtCore, QtWidgets, QtNetwork
|
from PyQt5 import QtGui, QtCore, QtWidgets, QtNetwork
|
||||||
from xml.sax.saxutils import escape
|
from xml.sax.saxutils import escape
|
||||||
from psutil import Popen, Process
|
from psutil import Process
|
||||||
from copy import copy
|
from copy import copy
|
||||||
from distutils.version import StrictVersion
|
from distutils.version import StrictVersion
|
||||||
from raven import Client
|
from raven import Client
|
||||||
from tempfile import gettempdir
|
from tempfile import gettempdir
|
||||||
from .shared import md5Checksum, HTMLStripper, sanitizeTrace, walkLevel
|
from .shared import md5Checksum, HTMLStripper, sanitizeTrace, walkLevel, subprocess_run_silent
|
||||||
from . import __version__
|
from . import __version__
|
||||||
from . import comic2ebook
|
from . import comic2ebook
|
||||||
from . import metadata
|
from . import metadata
|
||||||
@@ -139,10 +139,7 @@ class VersionThread(QtCore.QThread):
|
|||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
try:
|
try:
|
||||||
last_version_url = urlopen("https://api.github.com/repos/ciromattia/kcc/releases/latest")
|
json_parser = requests.get("https://api.github.com/repos/ciromattia/kcc/releases/latest").json()
|
||||||
data = last_version_url.read()
|
|
||||||
encoding = last_version_url.info().get_content_charset('utf-8')
|
|
||||||
json_parser = json.loads(data.decode(encoding))
|
|
||||||
|
|
||||||
html_url = json_parser["html_url"]
|
html_url = json_parser["html_url"]
|
||||||
latest_version = json_parser["tag_name"]
|
latest_version = json_parser["tag_name"]
|
||||||
@@ -752,7 +749,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
|
|
||||||
def display_kindlegen_missing(self):
|
def display_kindlegen_missing(self):
|
||||||
self.addMessage(
|
self.addMessage(
|
||||||
'<a href="https://github.com/ciromattia/kcc/wiki/Installation#kindlegen"><b>Cannot find KindleGen</b></a>: MOBI conversion is unavailable!',
|
'<a href="https://github.com/ciromattia/kcc#kindlegen"><b>Install KindleGen (link)</b></a> to enable MOBI conversion for Kindles!',
|
||||||
'error'
|
'error'
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -839,32 +836,21 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
os.chmod('/usr/local/bin/kindlegen', 0o755)
|
os.chmod('/usr/local/bin/kindlegen', 0o755)
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
kindleGenExitCode = Popen('kindlegen -locale en', stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=True)
|
try:
|
||||||
kindleGenExitCode.communicate()
|
versionCheck = subprocess_run_silent(['kindlegen', '-locale', 'en'], stdout=PIPE, stderr=STDOUT, encoding='UTF-8')
|
||||||
if kindleGenExitCode.returncode == 0:
|
|
||||||
self.kindleGen = True
|
self.kindleGen = True
|
||||||
versionCheck = Popen('kindlegen -locale en', stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=True)
|
for line in versionCheck.stdout.splitlines():
|
||||||
for line in versionCheck.stdout:
|
|
||||||
line = line.decode("utf-8")
|
|
||||||
if 'Amazon kindlegen' in line:
|
if 'Amazon kindlegen' in line:
|
||||||
versionCheck = line.split('V')[1].split(' ')[0]
|
versionCheck = line.split('V')[1].split(' ')[0]
|
||||||
if StrictVersion(versionCheck) < StrictVersion('2.9'):
|
if StrictVersion(versionCheck) < StrictVersion('2.9'):
|
||||||
self.addMessage('Your <a href="https://www.amazon.com/b?node=23496309011">KindleGen</a>'
|
self.addMessage('Your <a href="https://www.amazon.com/b?node=23496309011">KindleGen</a>'
|
||||||
' is outdated! MOBI conversion might fail.', 'warning')
|
' is outdated! MOBI conversion might fail.', 'warning')
|
||||||
break
|
break
|
||||||
where_command = 'where kindlegen.exe'
|
except FileNotFoundError:
|
||||||
if os.name == 'posix':
|
|
||||||
where_command = 'which kindlegen'
|
|
||||||
process = subprocess.run(where_command, stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=True)
|
|
||||||
locations = process.stdout.decode('utf-8').split('\n')
|
|
||||||
self.addMessage(f"<b>KindleGen Found:</b> {locations[0]}", 'info')
|
|
||||||
else:
|
|
||||||
self.kindleGen = False
|
self.kindleGen = False
|
||||||
if startup:
|
if startup:
|
||||||
self.display_kindlegen_missing()
|
self.display_kindlegen_missing()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, kccapp, kccwindow):
|
def __init__(self, kccapp, kccwindow):
|
||||||
global APP, MW, GUI
|
global APP, MW, GUI
|
||||||
APP = kccapp
|
APP = kccapp
|
||||||
@@ -943,7 +929,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
'DefaultUpscale': True, 'Label': 'KV'},
|
'DefaultUpscale': True, 'Label': 'KV'},
|
||||||
"Kindle PW 1/2": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
"Kindle PW 1/2": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
||||||
'DefaultUpscale': False, 'Label': 'KPW'},
|
'DefaultUpscale': False, 'Label': 'KPW'},
|
||||||
"Kindle": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
"Kindle 4/5/7/8/10": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
||||||
'DefaultUpscale': False, 'Label': 'K578'},
|
'DefaultUpscale': False, 'Label': 'K578'},
|
||||||
"Kindle DX/DXG": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 2,
|
"Kindle DX/DXG": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 2,
|
||||||
'DefaultUpscale': False, 'Label': 'KDX'},
|
'DefaultUpscale': False, 'Label': 'KDX'},
|
||||||
@@ -1011,7 +997,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
"Kindle Voyage",
|
"Kindle Voyage",
|
||||||
"Kindle 2",
|
"Kindle 2",
|
||||||
"Kindle 1",
|
"Kindle 1",
|
||||||
"Kindle",
|
"Kindle 4/5/7/8/10",
|
||||||
"Separator",
|
"Separator",
|
||||||
"Kobo Aura",
|
"Kobo Aura",
|
||||||
"Kobo Aura ONE",
|
"Kobo Aura ONE",
|
||||||
@@ -1039,14 +1025,13 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
self.addMessage('Since you are a new user of <b>KCC</b> please see few '
|
self.addMessage('Since you are a new user of <b>KCC</b> please see few '
|
||||||
'<a href="https://github.com/ciromattia/kcc/wiki/Important-tips">important tips</a>.',
|
'<a href="https://github.com/ciromattia/kcc/wiki/Important-tips">important tips</a>.',
|
||||||
'info')
|
'info')
|
||||||
process = Popen('7z', stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=True)
|
try:
|
||||||
process.communicate()
|
subprocess_run_silent(['7z'], stdout=PIPE, stderr=STDOUT)
|
||||||
if process.returncode == 0 or process.returncode == 7:
|
|
||||||
self.sevenzip = True
|
self.sevenzip = True
|
||||||
else:
|
except FileNotFoundError:
|
||||||
self.sevenzip = False
|
self.sevenzip = False
|
||||||
self.addMessage('<a href="https://github.com/ciromattia/kcc/wiki/Installation#7-zip">Cannot find 7z</a>!'
|
self.addMessage('<a href="https://github.com/ciromattia/kcc#7-zip">Install 7z (link)</a>'
|
||||||
' CBZ/CBR/ZIP/etc processing disabled.', 'warning')
|
' to enable CBZ/CBR/ZIP/etc processing.', 'warning')
|
||||||
self.detectKindleGen(True)
|
self.detectKindleGen(True)
|
||||||
|
|
||||||
APP.messageFromOtherInstance.connect(self.handleMessage)
|
APP.messageFromOtherInstance.connect(self.handleMessage)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
__version__ = '5.6.3'
|
__version__ = '5.6.5'
|
||||||
__license__ = 'ISC'
|
__license__ = 'ISC'
|
||||||
__copyright__ = '2012-2022, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>, darodi'
|
__copyright__ = '2012-2022, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>, darodi'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|||||||
@@ -19,6 +19,9 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import pathlib
|
||||||
|
import re
|
||||||
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
from time import strftime, gmtime
|
from time import strftime, gmtime
|
||||||
@@ -31,16 +34,17 @@ from tempfile import mkdtemp, gettempdir, TemporaryFile
|
|||||||
from shutil import move, copytree, rmtree, copyfile
|
from shutil import move, copytree, rmtree, copyfile
|
||||||
from multiprocessing import Pool
|
from multiprocessing import Pool
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
|
from natsort import os_sorted
|
||||||
from slugify import slugify as slugify_ext
|
from slugify import slugify as slugify_ext
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
from subprocess import STDOUT, PIPE
|
from subprocess import STDOUT, PIPE
|
||||||
from psutil import Popen, virtual_memory, disk_usage
|
from psutil import virtual_memory, disk_usage
|
||||||
from html import escape as hescape
|
from html import escape as hescape
|
||||||
try:
|
try:
|
||||||
from PyQt5 import QtCore
|
from PyQt5 import QtCore
|
||||||
except ImportError:
|
except ImportError:
|
||||||
QtCore = None
|
QtCore = None
|
||||||
from .shared import md5Checksum, getImageFileName, walkSort, walkLevel, sanitizeTrace
|
from .shared import md5Checksum, getImageFileName, walkSort, walkLevel, sanitizeTrace, subprocess_run_silent
|
||||||
from . import comic2panel
|
from . import comic2panel
|
||||||
from . import image
|
from . import image
|
||||||
from . import comicarchive
|
from . import comicarchive
|
||||||
@@ -671,11 +675,9 @@ def getOutputFilename(srcpath, wantedname, ext, tomenumber):
|
|||||||
filename = srcpath + tomenumber + ext
|
filename = srcpath + tomenumber + ext
|
||||||
else:
|
else:
|
||||||
if 'Ko' in options.profile and options.format == 'EPUB':
|
if 'Ko' in options.profile and options.format == 'EPUB':
|
||||||
path = srcpath.split(os.path.sep)
|
src = pathlib.Path(srcpath)
|
||||||
path[-1] = ''.join(e for e in path[-1].split('.')[0] if e.isalnum()) + tomenumber + ext
|
name = re.sub(r'\W+', '_', src.stem) + tomenumber + ext
|
||||||
if not path[-1].split('.')[0]:
|
filename = src.with_name(name)
|
||||||
path[-1] = 'KCCPlaceholder' + tomenumber + ext
|
|
||||||
filename = os.path.sep.join(path)
|
|
||||||
else:
|
else:
|
||||||
filename = os.path.splitext(srcpath)[0] + tomenumber + ext
|
filename = os.path.splitext(srcpath)[0] + tomenumber + ext
|
||||||
if os.path.isfile(filename):
|
if os.path.isfile(filename):
|
||||||
@@ -726,7 +728,7 @@ def getComicInfo(path, originalpath):
|
|||||||
options.authors.sort()
|
options.authors.sort()
|
||||||
else:
|
else:
|
||||||
options.authors = ['KCC']
|
options.authors = ['KCC']
|
||||||
if xml.data['Bookmarks']:
|
if xml.data['Bookmarks'] and options.batchsplit == 0:
|
||||||
options.chapters = xml.data['Bookmarks']
|
options.chapters = xml.data['Bookmarks']
|
||||||
if xml.data['Summary']:
|
if xml.data['Summary']:
|
||||||
options.summary = hescape(xml.data['Summary'])
|
options.summary = hescape(xml.data['Summary'])
|
||||||
@@ -761,7 +763,7 @@ def getPanelViewSize(deviceres, size):
|
|||||||
def sanitizeTree(filetree):
|
def sanitizeTree(filetree):
|
||||||
chapterNames = {}
|
chapterNames = {}
|
||||||
for root, dirs, files in os.walk(filetree, False):
|
for root, dirs, files in os.walk(filetree, False):
|
||||||
for i, name in enumerate(sorted(files)):
|
for i, name in enumerate(os_sorted(files)):
|
||||||
splitname = os.path.splitext(name)
|
splitname = os.path.splitext(name)
|
||||||
|
|
||||||
# file needs kcc at front AND back to avoid renaming issues
|
# file needs kcc at front AND back to avoid renaming issues
|
||||||
@@ -1101,17 +1103,17 @@ def checkTools(source):
|
|||||||
source = source.upper()
|
source = source.upper()
|
||||||
if source.endswith('.CB7') or source.endswith('.7Z') or source.endswith('.RAR') or source.endswith('.CBR') or \
|
if source.endswith('.CB7') or source.endswith('.7Z') or source.endswith('.RAR') or source.endswith('.CBR') or \
|
||||||
source.endswith('.ZIP') or source.endswith('.CBZ'):
|
source.endswith('.ZIP') or source.endswith('.CBZ'):
|
||||||
process = Popen('7z', stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=True)
|
try:
|
||||||
process.communicate()
|
subprocess_run_silent(['7z'], stdout=PIPE, stderr=STDOUT)
|
||||||
if process.returncode != 0 and process.returncode != 7:
|
except FileNotFoundError:
|
||||||
print('ERROR: 7z is missing!')
|
print('ERROR: 7z is missing!')
|
||||||
exit(1)
|
sys.exit(1)
|
||||||
if options.format == 'MOBI':
|
if options.format == 'MOBI':
|
||||||
kindleGenExitCode = Popen('kindlegen -locale en', stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=True)
|
try:
|
||||||
kindleGenExitCode.communicate()
|
subprocess_run_silent(['kindlegen', '-locale', 'en'], stdout=PIPE, stderr=STDOUT)
|
||||||
if kindleGenExitCode.returncode != 0:
|
except FileNotFoundError:
|
||||||
print('ERROR: KindleGen is missing!')
|
print('ERROR: KindleGen is missing!')
|
||||||
exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
def checkPre(source):
|
def checkPre(source):
|
||||||
@@ -1265,10 +1267,9 @@ def makeMOBIWorker(item):
|
|||||||
kindlegenError = ''
|
kindlegenError = ''
|
||||||
try:
|
try:
|
||||||
if os.path.getsize(item) < 629145600:
|
if os.path.getsize(item) < 629145600:
|
||||||
output = Popen('kindlegen -dont_append_source -locale en "' + item + '"',
|
output = subprocess_run_silent(['kindlegen', '-dont_append_source', '-locale', 'en', item],
|
||||||
stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=True)
|
stdout=PIPE, stderr=STDOUT, encoding='UTF-8')
|
||||||
for line in output.stdout:
|
for line in output.stdout.splitlines():
|
||||||
line = line.decode('utf-8')
|
|
||||||
# ERROR: Generic error
|
# ERROR: Generic error
|
||||||
if "Error(" in line:
|
if "Error(" in line:
|
||||||
kindlegenErrorCode = 1
|
kindlegenErrorCode = 1
|
||||||
@@ -1279,7 +1280,6 @@ def makeMOBIWorker(item):
|
|||||||
if kindlegenErrorCode > 0:
|
if kindlegenErrorCode > 0:
|
||||||
break
|
break
|
||||||
if ":I1036: Mobi file built successfully" in line:
|
if ":I1036: Mobi file built successfully" in line:
|
||||||
output.communicate()
|
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
# ERROR: EPUB too big
|
# ERROR: EPUB too big
|
||||||
|
|||||||
@@ -22,11 +22,13 @@ import os
|
|||||||
import platform
|
import platform
|
||||||
import subprocess
|
import subprocess
|
||||||
import distro
|
import distro
|
||||||
from psutil import Popen
|
|
||||||
from shutil import move
|
from shutil import move
|
||||||
from subprocess import STDOUT, PIPE
|
from subprocess import STDOUT, PIPE
|
||||||
from xml.dom.minidom import parseString
|
from xml.dom.minidom import parseString
|
||||||
from xml.parsers.expat import ExpatError
|
from xml.parsers.expat import ExpatError
|
||||||
|
from .shared import subprocess_run_silent
|
||||||
|
|
||||||
|
EXTRACTION_ERROR = 'Failed to extract archive. Try extracting file outside of KCC.'
|
||||||
|
|
||||||
|
|
||||||
class ComicArchive:
|
class ComicArchive:
|
||||||
@@ -35,70 +37,54 @@ class ComicArchive:
|
|||||||
self.type = None
|
self.type = None
|
||||||
if not os.path.isfile(self.filepath):
|
if not os.path.isfile(self.filepath):
|
||||||
raise OSError('File not found.')
|
raise OSError('File not found.')
|
||||||
process = Popen('7z l -y -p1 "' + self.filepath + '"', stderr=STDOUT, stdout=PIPE, stdin=PIPE, shell=True)
|
process = subprocess_run_silent(['7z', 'l', '-y', '-p1', self.filepath], stderr=STDOUT, stdout=PIPE)
|
||||||
for line in process.stdout:
|
for line in process.stdout.splitlines():
|
||||||
if b'Type =' in line:
|
if b'Type =' in line:
|
||||||
self.type = line.rstrip().decode().split(' = ')[1].upper()
|
self.type = line.rstrip().decode().split(' = ')[1].upper()
|
||||||
break
|
break
|
||||||
process.communicate()
|
|
||||||
if process.returncode != 0 and distro.id() == 'fedora':
|
if process.returncode != 0 and distro.id() == 'fedora':
|
||||||
process = Popen('unrar l -y -p1 "' + self.filepath + '"', stderr=STDOUT, stdout=PIPE, stdin=PIPE, shell=True)
|
process = subprocess_run_silent(['unrar', 'l', '-y', '-p1', self.filepath], stderr=STDOUT, stdout=PIPE)
|
||||||
for line in process.stdout:
|
for line in process.stdout.splitlines():
|
||||||
if b'Details: ' in line:
|
if b'Details: ' in line:
|
||||||
self.type = line.rstrip().decode().split(' ')[1].upper()
|
self.type = line.rstrip().decode().split(' ')[1].upper()
|
||||||
break
|
break
|
||||||
process.communicate()
|
|
||||||
if process.returncode != 0:
|
if process.returncode != 0:
|
||||||
raise OSError('Archive is corrupted or encrypted.')
|
raise OSError(EXTRACTION_ERROR)
|
||||||
elif self.type not in ['7Z', 'RAR', 'RAR5', 'ZIP']:
|
|
||||||
raise OSError('Unsupported archive format.')
|
|
||||||
elif self.type not in ['7Z', 'RAR', 'RAR5', 'ZIP']:
|
|
||||||
raise OSError('Unsupported archive format.')
|
|
||||||
|
|
||||||
def extract(self, targetdir):
|
def extract(self, targetdir):
|
||||||
if not os.path.isdir(targetdir):
|
if not os.path.isdir(targetdir):
|
||||||
raise OSError('Target directory doesn\'t exist.')
|
raise OSError('Target directory doesn\'t exist.')
|
||||||
process = Popen('7z x -y -xr!__MACOSX -xr!.DS_Store -xr!thumbs.db -xr!Thumbs.db -o"' + targetdir + '" "' +
|
process = subprocess_run_silent(['7z', 'x', '-y', '-xr!__MACOSX', '-xr!.DS_Store', '-xr!thumbs.db', '-xr!Thumbs.db', '-o' + targetdir, self.filepath],
|
||||||
self.filepath + '"', stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=True)
|
stdout=PIPE, stderr=STDOUT)
|
||||||
process.communicate()
|
|
||||||
if process.returncode != 0 and distro.id() == 'fedora':
|
if process.returncode != 0 and distro.id() == 'fedora':
|
||||||
process = Popen('unrar x -y -x__MACOSX -x.DS_Store -xthumbs.db -xThumbs.db "' + self.filepath + '" "' +
|
process = subprocess_run_silent(['unrar', 'x', '-y', '-x__MACOSX', '-x.DS_Store', '-xthumbs.db', '-xThumbs.db', self.filepath, targetdir]
|
||||||
targetdir + '"', stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=True)
|
, stdout=PIPE, stderr=STDOUT)
|
||||||
process.communicate()
|
|
||||||
if process.returncode != 0:
|
if process.returncode != 0:
|
||||||
raise OSError('Failed to extract archive.')
|
raise OSError(EXTRACTION_ERROR)
|
||||||
elif process.returncode != 0 and platform.system() == 'Darwin':
|
elif process.returncode != 0 and platform.system() == 'Darwin':
|
||||||
process = subprocess.run(f"unar '{self.filepath}' -f -o '{targetdir}'",
|
process = subprocess_run_silent(['unar', self.filepath, '-f', '-o', targetdir],
|
||||||
stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=True)
|
stdout=PIPE, stderr=STDOUT)
|
||||||
if process.returncode != 0:
|
|
||||||
raise Exception(process.stdout.decode("utf-8"))
|
|
||||||
elif process.returncode != 0:
|
elif process.returncode != 0:
|
||||||
raise OSError('Failed to extract archive. Check if p7zip-rar is installed.')
|
raise OSError(EXTRACTION_ERROR)
|
||||||
tdir = os.listdir(targetdir)
|
tdir = os.listdir(targetdir)
|
||||||
if 'ComicInfo.xml' in tdir:
|
if 'ComicInfo.xml' in tdir:
|
||||||
tdir.remove('ComicInfo.xml')
|
tdir.remove('ComicInfo.xml')
|
||||||
if len(tdir) == 1 and os.path.isdir(os.path.join(targetdir, tdir[0])):
|
|
||||||
for f in os.listdir(os.path.join(targetdir, tdir[0])):
|
|
||||||
move(os.path.join(targetdir, tdir[0], f), targetdir)
|
|
||||||
os.rmdir(os.path.join(targetdir, tdir[0]))
|
|
||||||
return targetdir
|
return targetdir
|
||||||
|
|
||||||
def addFile(self, sourcefile):
|
def addFile(self, sourcefile):
|
||||||
if self.type in ['RAR', 'RAR5']:
|
if self.type in ['RAR', 'RAR5']:
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
process = Popen('7z a -y "' + self.filepath + '" "' + sourcefile + '"',
|
process = subprocess_run_silent(['7z', 'a', '-y', self.filepath, sourcefile],
|
||||||
stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=True)
|
stdout=PIPE, stderr=STDOUT)
|
||||||
process.communicate()
|
|
||||||
if process.returncode != 0:
|
if process.returncode != 0:
|
||||||
raise OSError('Failed to add the file.')
|
raise OSError('Failed to add the file.')
|
||||||
|
|
||||||
def extractMetadata(self):
|
def extractMetadata(self):
|
||||||
process = Popen('7z x -y -so "' + self.filepath + '" ComicInfo.xml',
|
process = subprocess_run_silent(['7z', 'x', '-y', '-so', self.filepath, 'ComicInfo.xml'],
|
||||||
stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=True)
|
stdout=PIPE, stderr=STDOUT)
|
||||||
xml = process.communicate()
|
|
||||||
if process.returncode != 0:
|
if process.returncode != 0:
|
||||||
raise OSError('Failed to extract archive.')
|
raise OSError(EXTRACTION_ERROR)
|
||||||
try:
|
try:
|
||||||
return parseString(xml[0])
|
return parseString(process.stdout)
|
||||||
except ExpatError:
|
except ExpatError:
|
||||||
return None
|
return None
|
||||||
|
|||||||
@@ -24,12 +24,7 @@ import mozjpeg_lossless_optimization
|
|||||||
from PIL import Image, ImageOps, ImageStat, ImageChops, ImageFilter
|
from PIL import Image, ImageOps, ImageStat, ImageChops, ImageFilter
|
||||||
from .shared import md5Checksum
|
from .shared import md5Checksum
|
||||||
|
|
||||||
# 0.045 was determined by
|
AUTO_CROP_THRESHOLD = 0.015
|
||||||
# 1200 / 824 = 1.456 (Kindle DX resolution)
|
|
||||||
# 2250 / 1500 = 1.5 (Typical manga page resolution)
|
|
||||||
# 1.5 - 1.456 < 0.045
|
|
||||||
# 0.045 / 1.5 = 0.03 (So maximum 3% of is cropped)
|
|
||||||
AUTO_CROP_THRESHOLD = 0.045
|
|
||||||
|
|
||||||
|
|
||||||
class ProfileData:
|
class ProfileData:
|
||||||
|
|||||||
@@ -31,8 +31,7 @@ class Kindle:
|
|||||||
def findDevice(self):
|
def findDevice(self):
|
||||||
for drive in reversed(psutil.disk_partitions(False)):
|
for drive in reversed(psutil.disk_partitions(False)):
|
||||||
if (drive[2] == 'FAT32' and drive[3] == 'rw,removable') or \
|
if (drive[2] == 'FAT32' and drive[3] == 'rw,removable') or \
|
||||||
(drive[2] == 'vfat' and 'rw' in drive[3]) or \
|
(drive[2] in ('vfat', 'msdos', 'FAT') and 'rw' in drive[3]):
|
||||||
(drive[2] == 'msdos' and 'rw' in drive[3]):
|
|
||||||
if os.path.isdir(os.path.join(drive[1], 'system')) and \
|
if os.path.isdir(os.path.join(drive[1], 'system')) and \
|
||||||
os.path.isdir(os.path.join(drive[1], 'documents')):
|
os.path.isdir(os.path.join(drive[1], 'documents')):
|
||||||
return drive[1]
|
return drive[1]
|
||||||
|
|||||||
@@ -21,8 +21,10 @@
|
|||||||
import os
|
import os
|
||||||
from hashlib import md5
|
from hashlib import md5
|
||||||
from html.parser import HTMLParser
|
from html.parser import HTMLParser
|
||||||
|
import subprocess
|
||||||
from distutils.version import StrictVersion
|
from distutils.version import StrictVersion
|
||||||
from re import split
|
from re import split
|
||||||
|
import sys
|
||||||
from traceback import format_tb
|
from traceback import format_tb
|
||||||
|
|
||||||
|
|
||||||
@@ -133,4 +135,9 @@ def dependencyCheck(level):
|
|||||||
missing.append('Pillow 5.2.0+')
|
missing.append('Pillow 5.2.0+')
|
||||||
if len(missing) > 0:
|
if len(missing) > 0:
|
||||||
print('ERROR: ' + ', '.join(missing) + ' is not installed!')
|
print('ERROR: ' + ', '.join(missing) + ' is not installed!')
|
||||||
exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
def subprocess_run_silent(command, **kwargs):
|
||||||
|
if (os.name == 'nt'):
|
||||||
|
kwargs.setdefault('creationflags', subprocess.CREATE_NO_WINDOW)
|
||||||
|
return subprocess.run(command, **kwargs)
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
PyQt5>=5.6.0
|
PyQt5>=5.6.0
|
||||||
Pillow>=5.2.0
|
Pillow>=5.2.0
|
||||||
psutil>=5.0.0
|
psutil>=5.0.0
|
||||||
|
requests>=2.31.0
|
||||||
python-slugify>=1.2.1
|
python-slugify>=1.2.1
|
||||||
raven>=6.0.0
|
raven>=6.0.0
|
||||||
# PyQt5-tools
|
# PyQt5-tools
|
||||||
mozjpeg-lossless-optimization>=1.1.2
|
mozjpeg-lossless-optimization>=1.1.2
|
||||||
|
natsort[fast]>=8.4.0
|
||||||
distro
|
distro
|
||||||
|
|||||||
13
setup.py
13
setup.py
@@ -37,19 +37,19 @@ class BuildBinaryCommand(distutils.cmd.Command):
|
|||||||
def run(self):
|
def run(self):
|
||||||
VERSION = __version__
|
VERSION = __version__
|
||||||
if sys.platform == 'darwin':
|
if sys.platform == 'darwin':
|
||||||
os.system('pyinstaller -y -F -i icons/comic2ebook.icns -n "Kindle Comic Converter" -w -s kcc.py')
|
os.system('pyinstaller -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
|
# 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('appdmg kcc.json dist/KindleComicConverter_osx_' + VERSION + '.dmg')
|
||||||
exit(0)
|
sys.exit(0)
|
||||||
elif sys.platform == 'win32':
|
elif sys.platform == 'win32':
|
||||||
os.system('pyinstaller -y -F -i icons\\comic2ebook.ico -n KCC_' + VERSION + ' -w --noupx kcc.py')
|
os.system('pyinstaller -y -F -i icons\\comic2ebook.ico -n KCC_' + VERSION + ' -w --noupx kcc.py')
|
||||||
exit(0)
|
sys.exit(0)
|
||||||
elif sys.platform == 'linux':
|
elif sys.platform == 'linux':
|
||||||
os.system(
|
os.system(
|
||||||
'pyinstaller --hidden-import=queue -y -F -i icons/comic2ebook.ico -n kcc_linux_' + VERSION + ' kcc.py')
|
'pyinstaller --hidden-import=queue -y -F -i icons/comic2ebook.ico -n kcc_linux_' + VERSION + ' kcc.py')
|
||||||
exit(0)
|
sys.exit(0)
|
||||||
else:
|
else:
|
||||||
exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
|
|
||||||
setuptools.setup(
|
setuptools.setup(
|
||||||
@@ -80,7 +80,10 @@ setuptools.setup(
|
|||||||
'psutil>=5.0.0',
|
'psutil>=5.0.0',
|
||||||
'python-slugify>=1.2.1,<9.0.0',
|
'python-slugify>=1.2.1,<9.0.0',
|
||||||
'raven>=6.0.0',
|
'raven>=6.0.0',
|
||||||
|
'requests>=2.31.0',
|
||||||
'mozjpeg-lossless-optimization>=1.1.2',
|
'mozjpeg-lossless-optimization>=1.1.2',
|
||||||
|
'natsort[fast]>=8.4.0',
|
||||||
|
'distro',
|
||||||
],
|
],
|
||||||
classifiers=[],
|
classifiers=[],
|
||||||
zip_safe=False,
|
zip_safe=False,
|
||||||
|
|||||||
Reference in New Issue
Block a user