1
0
mirror of https://github.com/ciromattia/kcc synced 2026-01-06 21:39:29 +00:00

Merge pull request #306 from ciromattia/dev

5.5.0
This commit is contained in:
Paweł Jastrzębski
2019-03-07 08:39:57 +01:00
committed by GitHub
40 changed files with 306 additions and 2490 deletions

View File

@@ -2,11 +2,11 @@ matrix:
include:
- os: osx
language: generic
osx_image: xcode6.4
osx_image: xcode9.2
before_install:
- brew update
- brew install python3
- brew upgrade python3
- brew uninstall node
- travis_wait 30 brew install node@6
- brew link node@6 --force --overwrite
@@ -15,7 +15,7 @@ before_install:
install:
- pip3 install -r requirements.txt
- pip3 install certifi https://github.com/bjones1/pyinstaller/archive/pyqt5_fix.zip
- pip3 install certifi https://github.com/pyinstaller/pyinstaller/archive/develop.zip
- npm install -g appdmg
script: python3 setup.py build_binary

View File

@@ -1,4 +1,11 @@
# CHANGELOG
#### 5.5.0:
* Added support for WebP format
* Added profiles for Kindle Paperwhite 4 and Kobo Forma
* All archives are now handled by 7z
* Removed MCD support
* Fixed multiple smaller issues
#### 5.4.5:
* Fixed EPUB output for non-Kindle devices

View File

@@ -1,7 +1,7 @@
ISC LICENSE
Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
Copyright (c) 2013-2018 Paweł Jastrzębski <pawelj@iosphe.re>
Copyright (c) 2013-2019 Paweł Jastrzębski <pawelj@iosphe.re>
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the

View File

@@ -28,11 +28,8 @@ If you find **KCC** valuable you can consider donating to the authors:
## BINARY RELEASES
You can find the latest released binary at the following links:
- **[Windows](http://kcc.iosphe.re/Windows/) (64-bit only)**
- **[macOS](http://kcc.iosphe.re/OSX/) (10.10+)**
- **Linux:**
- [Ubuntu 17.10](http://kcc.iosphe.re/LinuxArtful/)
- [Ubuntu 16.04 / Debian 9](http://kcc.iosphe.re/LinuxXenial/)
- [Ubuntu 14.04 / Debian 8](http://kcc.iosphe.re/LinuxTrusty/)
- **[macOS](http://kcc.iosphe.re/OSX/) (10.12+)**
- **Linux:** Currently unavailable.
## PYPI
**KCC** is also available on PyPI.
@@ -51,21 +48,20 @@ Following software is required to run Linux version of **KCC** and/or bare sourc
On Debian based distributions these two commands should install all needed dependencies:
```
sudo apt-get install python3 python3-dev python3-pip libpng-dev libjpeg-dev p7zip-full unrar
sudo apt-get install python3 python3-dev python3-pip libpng-dev libjpeg-dev p7zip-full
sudo pip3 install --upgrade pillow python-slugify psutil pyqt5 raven
```
### Optional dependencies
- [KindleGen](http://www.amazon.com/gp/feature.html?ie=UTF8&docId=1000765211) v2.9+ in a directory reachable by your _PATH_ or in _KCC_ directory *(For MOBI generation)*
- [UnRAR](http://www.rarlab.com/download.htm) *(For CBR/RAR support)*
- [7za](http://www.7-zip.org/download.html) *(For 7z/CB7 support)*
- [7z](http://www.7-zip.org/download.html) *(For CBZ/ZIP, CBR/RAR, 7z/CB7 support)*
## INPUT FORMATS
**KCC** can understand and convert, at the moment, the following input types:
- Folders containing: PNG, JPG or GIF files
- CBZ, ZIP
- CBR, RAR *(With `unrar` executable)*
- CB7, 7Z *(With `7za` executable)*
- Folders containing: PNG, JPG, GIF or WebP files
- CBZ, ZIP *(With `7z` executable)*
- CBR, RAR *(With `7z` executable)*
- CB7, 7Z *(With `7z` executable)*
- PDF *(Only extracting JPG images)*
## USAGE
@@ -87,7 +83,7 @@ Options:
-p PROFILE, --profile=PROFILE
Device profile (Available options: K1, K2, K34, K578,
KDX, KPW, KV, KO, KoMT, KoG, KoGHD, KoA, KoAHD, KoAH2O,
KoAO) [Default=KV]
KoAO, KoF) [Default=KV]
-m, --manga-style Manga style (right-to-left reading and splitting)
-q, --hq Try to increase the quality of magnification
-2, --two-panel Display two not four panels in Panel View mode
@@ -160,29 +156,28 @@ This script born as a cross-platform alternative to `KindleComicParser` by **Dc5
The app relies and includes the following scripts:
- `DualMetaFix` script by **K. Hendricks**. Released with GPL-3 License.
- `rarfile.py` script &copy; 2005-2014 **Marko Kreen** <markokr@gmail.com>. Released with ISC License.
- `image.py` class from **Alex Yatskov**'s [Mangle](https://github.com/FooSoft/mangle/) with subsequent [proDOOMman](https://github.com/proDOOMman/Mangle)'s and [Birua](https://github.com/Birua/Mangle)'s patches.
- Icon is by **Nikolay Verin** ([http://ncrow.deviantart.com/](http://ncrow.deviantart.com/)) and released under [CC BY-NC-SA 3.0](http://creativecommons.org/licenses/by-nc-sa/3.0/) License.
## SAMPLE FILES CREATED BY KCC
* [Kindle Oasis 2](http://kcc.iosphe.re/Samples/Ubunchu!-KO.mobi)
* [Kindle Paperwhite 3 / Voyage / Oasis](http://kcc.iosphe.re/Samples/Ubunchu!-KV.mobi)
* [Kindle Paperwhite 3 / 4 / Voyage / Oasis](http://kcc.iosphe.re/Samples/Ubunchu!-KV.mobi)
* [Kindle Paperwhite 1 / 2](http://kcc.iosphe.re/Samples/Ubunchu!-KPW.mobi)
* [Kindle](http://kcc.iosphe.re/Samples/Ubunchu!-K578.mobi)
* [Kobo Aura](http://kcc.iosphe.re/Samples/Ubunchu-KoA.kepub.epub)
* [Kobo Aura HD](http://kcc.iosphe.re/Samples/Ubunchu-KoAHD.kepub.epub)
* [Kobo Aura H2O](http://kcc.iosphe.re/Samples/Ubunchu-KoAH2O.kepub.epub)
* [Kobo Aura ONE](http://kcc.iosphe.re/Samples/Ubunchu-KoAO.kepub.epub)
* [Kobo Forma](http://kcc.iosphe.re/Samples/Ubunchu-KoF.kepub.epub)
## PRIVACY
**KCC** is initiating internet connections in three cases:
* During startup - Version check
* When MCD metadata are used - Cover download
* When error occurs - Automatic reporting
**KCC** is initiating internet connections in two cases:
* During startup - Version check.
* When error occurs - Automatic reporting on Windows and MacOS.
## KNOWN ISSUES
Please check [wiki page](https://github.com/ciromattia/kcc/wiki/Known-issues).
## COPYRIGHT
Copyright (c) 2012-2018 Ciro Mattia Gonano and Paweł Jastrzębski.
Copyright (c) 2012-2019 Ciro Mattia Gonano and Paweł Jastrzębski.
**KCC** is released under ISC LICENSE; see LICENSE.txt for further details.

View File

@@ -1,11 +1,11 @@
environment:
PYTHON: "C:\\Python36-x64"
PYTHON: "C:\\Python37-x64"
install:
- set PATH="%PYTHON%\\Scripts";"C:\\Program Files (x86)\\Inno Setup 5";%PATH%
- "%PYTHON%\\python.exe -m pip install --upgrade pip setuptools wheel"
- "%PYTHON%\\python.exe -m pip install -r requirements.txt"
- "%PYTHON%\\python.exe -m pip install certifi https://github.com/bjones1/pyinstaller/archive/pyqt5_fix.zip"
- "%PYTHON%\\python.exe -m pip install certifi https://github.com/pyinstaller/pyinstaller/archive/develop.zip"
- nuget install secure-file -ExcludeVersion
- secure-file\tools\secure-file -decrypt other\windows\sentry.py.enc -out kindlecomicconverter\sentry.py -secret %ENCRYPTION%

View File

@@ -112,19 +112,6 @@
<item row="6" column="1">
<widget class="QLineEdit" name="coloristLine"/>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/ciromattia/kcc/wiki/Manga-Cover-Database-support&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;MUid:&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QLineEdit" name="muidLine"/>
</item>
</layout>
</widget>
</item>

View File

@@ -2,7 +2,7 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
# Copyright (c) 2013-2018 Pawel Jastrzebski <pawelj@iosphe.re>
# Copyright (c) 2013-2019 Pawel Jastrzebski <pawelj@iosphe.re>
#
# Permission to use, copy, modify, and/or distribute this software for
# any purpose with or without fee is hereby granted, provided that the

View File

@@ -2,7 +2,7 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
# Copyright (c) 2013-2018 Pawel Jastrzebski <pawelj@iosphe.re>
# Copyright (c) 2013-2019 Pawel Jastrzebski <pawelj@iosphe.re>
#
# Permission to use, copy, modify, and/or distribute this software for
# any purpose with or without fee is hereby granted, provided that the

View File

@@ -1,5 +1,5 @@
#define MyAppName "Kindle Comic Converter"
#define MyAppVersion "5.4.5"
#define MyAppVersion "5.5.0"
#define MyAppPublisher "Ciro Mattia Gonano, Paweł Jastrzębski"
#define MyAppURL "http://kcc.iosphe.re/"
#define MyAppExeName "KCC.exe"
@@ -12,7 +12,7 @@ AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
AppCopyright=Copyright (C) 2012-2018 Ciro Mattia Gonano and Paweł Jastrzębski
AppCopyright=Copyright (C) 2012-2019 Ciro Mattia Gonano and Paweł Jastrzębski
ArchitecturesAllowed=x64
DefaultDirName={pf}\{#MyAppName}
DefaultGroupName={#MyAppName}
@@ -47,8 +47,8 @@ Name: "CB7association"; Description: "CB7"; GroupDescription: "File associations
Source: "dist\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion
Source: "LICENSE.txt"; DestDir: "{app}"; Flags: ignoreversion solidbreak
Source: "other\windows\Additional-LICENSE.txt"; DestDir: "{app}"; Flags: ignoreversion
Source: "other\windows\UnRAR.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "other\windows\7za.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "other\windows\7z.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "other\windows\7z.dll"; DestDir: "{app}"; Flags: ignoreversion
[Icons]
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"

2
kcc.py
View File

@@ -2,7 +2,7 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
# Copyright (c) 2013-2018 Pawel Jastrzebski <pawelj@iosphe.re>
# Copyright (c) 2013-2019 Pawel Jastrzebski <pawelj@iosphe.re>
#
# Permission to use, copy, modify, and/or distribute this software for
# any purpose with or without fee is hereby granted, provided that the

View File

@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
# Copyright (c) 2013-2018 Pawel Jastrzebski <pawelj@iosphe.re>
# Copyright (c) 2013-2019 Pawel Jastrzebski <pawelj@iosphe.re>
#
# Permission to use, copy, modify, and/or distribute this software for
# any purpose with or without fee is hereby granted, provided that the
@@ -22,8 +22,9 @@ import sys
from urllib.parse import unquote
from urllib.request import urlopen, urlretrieve, Request
from time import sleep
from shutil import move
from shutil import move, rmtree
from subprocess import STDOUT, PIPE
# noinspection PyUnresolvedReferences
from PyQt5 import QtGui, QtCore, QtWidgets, QtNetwork
from xml.dom.minidom import parse
from xml.sax.saxutils import escape
@@ -31,7 +32,8 @@ from psutil import Popen, Process
from copy import copy
from distutils.version import StrictVersion
from raven import Client
from .shared import md5Checksum, HTMLStripper, sanitizeTrace
from tempfile import gettempdir
from .shared import md5Checksum, HTMLStripper, sanitizeTrace, walkLevel
from . import __version__
from . import comic2ebook
from . import metadata
@@ -173,7 +175,7 @@ class VersionThread(QtCore.QThread):
move(path[0], path[0] + '.exe')
MW.hideProgressBar.emit()
MW.modeConvert.emit(1)
Popen(path[0] + '.exe /SP- /silent /noicons', stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=True)
Popen(path[0] + '.exe /SP- /silent /noicons', stdout=PIPE, stderr=STDOUT, shell=True)
MW.forceShutdown.emit()
except Exception:
MW.addMessage.emit('Failed to download the update!', 'warning', False)
@@ -238,6 +240,7 @@ class WorkerThread(QtCore.QThread):
MW.addTrayMessage.emit('Conversion interrupted.', 'Critical')
MW.modeConvert.emit(1)
# noinspection PyUnboundLocalVariable
def run(self):
MW.modeConvert.emit(0)
@@ -477,20 +480,11 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
if self.needClean:
self.needClean = False
GUI.jobList.clear()
if self.UnRAR:
if self.sevenza:
fnames = QtWidgets.QFileDialog.getOpenFileNames(MW, 'Select file', self.lastPath,
'Comic (*.cbz *.cbr *.cb7 *.zip *.rar *.7z *.pdf)')
else:
fnames = QtWidgets.QFileDialog.getOpenFileNames(MW, 'Select file', self.lastPath,
'Comic (*.cbz *.cbr *.zip *.rar *.pdf)')
if self.sevenzip:
fnames = QtWidgets.QFileDialog.getOpenFileNames(MW, 'Select file', self.lastPath,
'Comic (*.cbz *.cbr *.cb7 *.zip *.rar *.7z *.pdf)')
else:
if self.sevenza:
fnames = QtWidgets.QFileDialog.getOpenFileNames(MW, 'Select file', self.lastPath,
'Comic (*.cbz *.cb7 *.zip *.7z *.pdf)')
else:
fnames = QtWidgets.QFileDialog.getOpenFileNames(MW, 'Select file', self.lastPath,
'Comic (*.cbz *.zip *.pdf)')
fnames = QtWidgets.QFileDialog.getOpenFileNames(MW, 'Select file', self.lastPath, 'Comic (*.pdf)')
for fname in fnames[0]:
if fname != '':
if sys.platform.startswith('win'):
@@ -509,20 +503,12 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
sname = sname.replace('/', '\\')
self.lastPath = os.path.abspath(sname)
else:
if self.UnRAR:
if self.sevenza:
fname = QtWidgets.QFileDialog.getOpenFileName(MW, 'Select file', self.lastPath,
'Comic (*.cbz *.cbr *.cb7)')
else:
fname = QtWidgets.QFileDialog.getOpenFileName(MW, 'Select file', self.lastPath,
'Comic (*.cbz *.cbr)')
if self.sevenzip:
fname = QtWidgets.QFileDialog.getOpenFileName(MW, 'Select file', self.lastPath,
'Comic (*.cbz *.cbr *.cb7)')
else:
if self.sevenza:
fname = QtWidgets.QFileDialog.getOpenFileName(MW, 'Select file', self.lastPath,
'Comic (*.cbz *.cb7)')
else:
fname = QtWidgets.QFileDialog.getOpenFileName(MW, 'Select file', self.lastPath,
'Comic (*.cbz)')
fname = ['']
self.showDialog("Editor is disabled due to a lack of 7z.", 'error')
if fname[0] != '':
if sys.platform.startswith('win'):
sname = fname[0].replace('/', '\\')
@@ -812,16 +798,9 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
if self.needClean:
self.needClean = False
GUI.jobList.clear()
if self.UnRAR:
if self.sevenza:
formats = ['.cbz', '.cbr', '.cb7', '.zip', '.rar', '.7z', '.pdf']
else:
formats = ['.cbz', '.cbr', '.zip', '.rar', '.pdf']
else:
if self.sevenza:
formats = ['.cbz', '.cb7', '.zip', '.7z', '.pdf']
else:
formats = ['.cbz', '.zip', '.pdf']
formats = ['.pdf']
if self.sevenzip:
formats.extend(['.cb7', '.7z', '.cbz', '.zip', '.cbr', '.rar'])
if os.path.isdir(message):
GUI.jobList.addItem(message)
GUI.jobList.scrollToBottom()
@@ -831,7 +810,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
GUI.jobList.addItem(message)
GUI.jobList.scrollToBottom()
else:
self.addMessage('This file type is unsupported!', 'error')
self.addMessage('Unsupported file type for ' + message, 'error')
def dragAndDrop(self, e):
e.accept()
@@ -857,10 +836,11 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
os.chmod('/usr/local/bin/kindlegen', 0o755)
except Exception:
pass
kindleGenExitCode = Popen('kindlegen -locale en', stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=True)
if kindleGenExitCode.wait() == 0:
kindleGenExitCode = Popen('kindlegen -locale en', stdout=PIPE, stderr=STDOUT, shell=True)
kindleGenExitCode.communicate()
if kindleGenExitCode.returncode == 0:
self.kindleGen = True
versionCheck = Popen('kindlegen -locale en', stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=True)
versionCheck = Popen('kindlegen -locale en', stdout=PIPE, stderr=STDOUT, shell=True)
for line in versionCheck.stdout:
line = line.decode("utf-8")
if 'Amazon kindlegen' in line:
@@ -909,6 +889,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
self.targetDirectory = ''
self.sentry = Client(release=__version__)
if sys.platform.startswith('win'):
# noinspection PyUnresolvedReferences
from psutil import BELOW_NORMAL_PRIORITY_CLASS
self.p = Process(os.getpid())
self.p.nice(BELOW_NORMAL_PRIORITY_CLASS)
@@ -934,8 +915,8 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
'DefaultUpscale': True, 'Label': 'KV'},
"Kindle Voyage": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
'DefaultUpscale': True, 'Label': 'KV'},
"Kindle PW 3": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
'DefaultUpscale': True, 'Label': 'KV'},
"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": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
@@ -956,6 +937,8 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
'DefaultUpscale': True, 'Label': 'KoAH2O'},
"Kobo Aura ONE": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1,
'DefaultUpscale': True, 'Label': 'KoAO'},
"Kobo Forma": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1,
'DefaultUpscale': True, 'Label': 'KoF'},
"Other": {'PVOptions': False, 'ForceExpert': True, 'DefaultFormat': 1,
'DefaultUpscale': False, 'Label': 'OTHER'},
"Kindle 1": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 0,
@@ -971,10 +954,11 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
"Kindle Oasis 2",
"Kindle Oasis",
"Kindle Voyage",
"Kindle PW 3",
"Kindle PW 3/4",
"Kindle PW 1/2",
"Kindle",
"Separator",
"Kobo Forma",
"Kobo Aura ONE",
"Kobo Aura H2O",
"Kobo Aura HD",
@@ -1007,22 +991,14 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
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>.',
'info')
rarExitCode = Popen('unrar', stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=True)
rarExitCode = rarExitCode.wait()
if rarExitCode == 0 or rarExitCode == 1 or rarExitCode == 7:
self.UnRAR = True
process = Popen('7z', stdout=PIPE, stderr=STDOUT, shell=True)
process.communicate()
if process.returncode == 0 or process.returncode == 7:
self.sevenzip = True
else:
self.UnRAR = False
self.addMessage('Cannot find <a href="http://www.rarlab.com/rar_add.htm">UnRAR</a>!'
' Processing of CBR/RAR files will be disabled.', 'warning')
sevenzaExitCode = Popen('7za', stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=True)
sevenzaExitCode = sevenzaExitCode.wait()
if sevenzaExitCode == 0 or sevenzaExitCode == 7:
self.sevenza = True
else:
self.sevenza = False
self.addMessage('Cannot find <a href="http://www.7-zip.org/download.html">7za</a>!'
' Processing of CB7/7Z files will be disabled.', 'warning')
self.sevenzip = False
self.addMessage('Cannot find <a href="http://www.7-zip.org/download.html">7z</a>!'
' Processing of archives will be disabled.', 'warning')
self.detectKindleGen(True)
APP.messageFromOtherInstance.connect(self.handleMessage)
@@ -1092,6 +1068,12 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
self.versionCheck.start()
self.tray.show()
# Cleanup unfisnished conversion
for root, dirs, _ in walkLevel(gettempdir(), 0):
for tempdir in dirs:
if tempdir.startswith('KCC-'):
rmtree(os.path.join(root, tempdir), True)
if self.windowSize != '0x0':
x, y = self.windowSize.split('x')
MW.resize(int(x), int(y))
@@ -1103,7 +1085,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
class KCCGUI_MetaEditor(KCC_ui_editor.Ui_editorDialog):
def loadData(self, file):
self.parser = metadata.MetadataParser(file)
if self.parser.compressor == 'rar':
if self.parser.format in ['RAR', 'RAR5']:
self.editorWidget.setEnabled(False)
self.okButton.setEnabled(False)
self.statusLabel.setText('CBR metadata are read-only.')
@@ -1111,11 +1093,8 @@ class KCCGUI_MetaEditor(KCC_ui_editor.Ui_editorDialog):
self.editorWidget.setEnabled(True)
self.okButton.setEnabled(True)
self.statusLabel.setText('Separate authors with a comma.')
for field in (self.seriesLine, self.volumeLine, self.numberLine, self.muidLine):
if field.objectName() == 'muidLine':
field.setText(self.parser.data['MUid'])
else:
field.setText(self.parser.data[field.objectName().capitalize()[:-4]])
for field in (self.seriesLine, self.volumeLine, self.numberLine):
field.setText(self.parser.data[field.objectName().capitalize()[:-4]])
for field in (self.writerLine, self.pencillerLine, self.inkerLine, self.coloristLine):
field.setText(', '.join(self.parser.data[field.objectName().capitalize()[:-4] + 's']))
if self.seriesLine.text() == '':
@@ -1125,12 +1104,9 @@ class KCCGUI_MetaEditor(KCC_ui_editor.Ui_editorDialog):
self.seriesLine.setText(file.split('\\')[-1].split('/')[-1].split('.')[0])
def saveData(self):
for field in (self.volumeLine, self.numberLine, self.muidLine):
for field in (self.volumeLine, self.numberLine):
if field.text().isnumeric() or self.cleanData(field.text()) == '':
if field.objectName() == 'muidLine':
self.parser.data['MUid'] = self.cleanData(field.text())
else:
self.parser.data[field.objectName().capitalize()[:-4]] = self.cleanData(field.text())
self.parser.data[field.objectName().capitalize()[:-4]] = self.cleanData(field.text())
else:
self.statusLabel.setText(field.objectName().capitalize()[:-4] + ' field must be a number.')
break

View File

@@ -66,13 +66,6 @@ class Ui_editorDialog(object):
self.coloristLine = QtWidgets.QLineEdit(self.editorWidget)
self.coloristLine.setObjectName("coloristLine")
self.gridLayout.addWidget(self.coloristLine, 6, 1, 1, 1)
self.label_8 = QtWidgets.QLabel(self.editorWidget)
self.label_8.setOpenExternalLinks(True)
self.label_8.setObjectName("label_8")
self.gridLayout.addWidget(self.label_8, 7, 0, 1, 1)
self.muidLine = QtWidgets.QLineEdit(self.editorWidget)
self.muidLine.setObjectName("muidLine")
self.gridLayout.addWidget(self.muidLine, 7, 1, 1, 1)
self.verticalLayout.addWidget(self.editorWidget)
self.optionWidget = QtWidgets.QWidget(editorDialog)
self.optionWidget.setObjectName("optionWidget")
@@ -117,7 +110,6 @@ class Ui_editorDialog(object):
self.label_5.setText(_translate("editorDialog", "Penciller:"))
self.label_6.setText(_translate("editorDialog", "Inker:"))
self.label_7.setText(_translate("editorDialog", "Colorist:"))
self.label_8.setText(_translate("editorDialog", "<html><head/><body><p><a href=\"https://github.com/ciromattia/kcc/wiki/Manga-Cover-Database-support\"><span style=\" text-decoration: underline; color:#0000ff;\">MUid:</span></a></p></body></html>"))
self.okButton.setText(_translate("editorDialog", "Save"))
self.cancelButton.setText(_translate("editorDialog", "Cancel"))

View File

@@ -1,4 +1,4 @@
__version__ = '5.4.5'
__version__ = '5.5.0'
__license__ = 'ISC'
__copyright__ = '2012-2018, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>'
__copyright__ = '2012-2019, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>'
__docformat__ = 'restructuredtext en'

View File

@@ -1,89 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
# Copyright (c) 2013-2018 Pawel Jastrzebski <pawelj@iosphe.re>
#
# Permission to use, copy, modify, and/or distribute this software for
# any purpose with or without fee is hereby granted, provided that the
# above copyright notice and this permission notice appear in all
# copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
# WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
# AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
# DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
# OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
#
import os
from zipfile import is_zipfile, ZipFile
from subprocess import STDOUT, PIPE
from psutil import Popen
from shutil import move
from . import rarfile
from .shared import check7ZFile as is_7zfile
class CBxArchive:
def __init__(self, fname):
self.fname = fname
if is_zipfile(fname):
self.compressor = 'zip'
elif rarfile.is_rarfile(fname):
self.compressor = 'rar'
elif is_7zfile(fname):
self.compressor = '7z'
else:
self.compressor = None
def isCbxFile(self):
return self.compressor is not None
def extractCBZ(self, targetdir):
cbzFile = ZipFile(self.fname)
filelist = []
for f in cbzFile.namelist():
if f.startswith('__MACOSX') or f.endswith('.DS_Store') or f.endswith('humbs.db'):
pass
elif f.endswith('/'):
os.makedirs(os.path.join(targetdir, f), exist_ok=True)
else:
filelist.append(f)
cbzFile.extractall(targetdir, filelist)
def extractCBR(self, targetdir):
cbrFile = rarfile.RarFile(self.fname)
cbrFile.extractall(targetdir)
for root, _, filenames in os.walk(targetdir):
for filename in filenames:
if filename.startswith('__MACOSX') or filename.endswith('.DS_Store') or filename.endswith('humbs.db'):
os.remove(os.path.join(root, filename))
def extractCB7(self, targetdir):
output = Popen('7za x "' + self.fname + '" -xr!__MACOSX -xr!.DS_Store -xr!thumbs.db -xr!Thumbs.db -o"' +
targetdir + '"', stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=True)
extracted = False
for line in output.stdout:
if b"Everything is Ok" in line:
extracted = True
if not extracted:
raise OSError
def extract(self, targetdir):
if self.compressor == 'rar':
self.extractCBR(targetdir)
elif self.compressor == 'zip':
self.extractCBZ(targetdir)
elif self.compressor == '7z':
self.extractCB7(targetdir)
adir = os.listdir(targetdir)
if 'ComicInfo.xml' in adir:
adir.remove('ComicInfo.xml')
if len(adir) == 1 and os.path.isdir(os.path.join(targetdir, adir[0])):
for f in os.listdir(os.path.join(targetdir, adir[0])):
move(os.path.join(targetdir, adir[0], f), targetdir)
os.rmdir(os.path.join(targetdir, adir[0]))
return targetdir

View File

@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
# Copyright (c) 2013-2018 Pawel Jastrzebski <pawelj@iosphe.re>
# Copyright (c) 2013-2019 Pawel Jastrzebski <pawelj@iosphe.re>
#
# Permission to use, copy, modify, and/or distribute this software for
# any purpose with or without fee is hereby granted, provided that the
@@ -22,9 +22,7 @@ import os
import sys
from time import strftime, gmtime
from copy import copy
from glob import glob
from json import loads
from urllib.request import Request, urlopen
from glob import glob, escape
from re import sub
from stat import S_IWRITE, S_IREAD, S_IEXEC
from zipfile import ZipFile, ZIP_STORED, ZIP_DEFLATED
@@ -37,7 +35,7 @@ from slugify import slugify as slugifyExt
from PIL import Image
from subprocess import STDOUT, PIPE
from psutil import Popen, virtual_memory, disk_usage
from html import escape
from html import escape as hescape
try:
from PyQt5 import QtCore
except ImportError:
@@ -45,7 +43,7 @@ except ImportError:
from .shared import md5Checksum, getImageFileName, walkSort, walkLevel, sanitizeTrace
from . import comic2panel
from . import image
from . import cbxarchive
from . import comicarchive
from . import pdfjpgextract
from . import dualmetafix
from . import metadata
@@ -61,7 +59,7 @@ def main(argv=None):
parser.print_help()
return 0
if sys.platform.startswith('win'):
sources = set([source for arg in args for source in glob(arg)])
sources = set([source for arg in args for source in glob(escape(arg))])
else:
sources = set(args)
if len(sources) == 0:
@@ -112,7 +110,7 @@ def buildHTML(path, imgfile, imgfilepath):
"<!DOCTYPE html>\n",
"<html xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:epub=\"http://www.idpf.org/2007/ops\">\n",
"<head>\n",
"<title>", escape(filename[0]), "</title>\n",
"<title>", hescape(filename[0]), "</title>\n",
"<link href=\"", "../" * (backref - 1), "style.css\" type=\"text/css\" rel=\"stylesheet\"/>\n",
"<meta name=\"viewport\" "
"content=\"width=" + str(imgsize[0]) + ", height=" + str(imgsize[1]) + "\"/>\n"
@@ -210,7 +208,7 @@ def buildNCX(dstdir, title, chapters, chapternames):
"<meta name=\"dtb:maxPageNumber\" content=\"0\"/>\n",
"<meta name=\"generated\" content=\"true\"/>\n",
"</head>\n",
"<docTitle><text>", escape(title), "</text></docTitle>\n",
"<docTitle><text>", hescape(title), "</text></docTitle>\n",
"<navMap>\n"])
for chapter in chapters:
folder = chapter[0].replace(os.path.join(dstdir, 'OEBPS'), '').lstrip('/').lstrip('\\\\')
@@ -222,7 +220,7 @@ def buildNCX(dstdir, title, chapters, chapternames):
elif os.path.basename(folder) != "Text":
title = chapternames[os.path.basename(folder)]
f.write("<navPoint id=\"" + navID + "\"><navLabel><text>" +
escape(title) + "</text></navLabel><content src=\"" + filename[0].replace("\\", "/") +
hescape(title) + "</text></navLabel><content src=\"" + filename[0].replace("\\", "/") +
".xhtml\"/></navPoint>\n")
f.write("</navMap>\n</ncx>")
f.close()
@@ -235,7 +233,7 @@ def buildNAV(dstdir, title, chapters, chapternames):
"<!DOCTYPE html>\n",
"<html xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:epub=\"http://www.idpf.org/2007/ops\">\n",
"<head>\n",
"<title>" + escape(title) + "</title>\n",
"<title>" + hescape(title) + "</title>\n",
"<meta charset=\"utf-8\"/>\n",
"</head>\n",
"<body>\n",
@@ -248,7 +246,7 @@ def buildNAV(dstdir, title, chapters, chapternames):
title = chapternames[chapter[1]]
elif os.path.basename(folder) != "Text":
title = chapternames[os.path.basename(folder)]
f.write("<li><a href=\"" + filename[0].replace("\\", "/") + ".xhtml\">" + escape(title) + "</a></li>\n")
f.write("<li><a href=\"" + filename[0].replace("\\", "/") + ".xhtml\">" + hescape(title) + "</a></li>\n")
f.writelines(["</ol>\n",
"</nav>\n",
"<nav epub:type=\"page-list\">\n",
@@ -260,7 +258,7 @@ def buildNAV(dstdir, title, chapters, chapternames):
title = chapternames[chapter[1]]
elif os.path.basename(folder) != "Text":
title = chapternames[os.path.basename(folder)]
f.write("<li><a href=\"" + filename[0].replace("\\", "/") + ".xhtml\">" + escape(title) + "</a></li>\n")
f.write("<li><a href=\"" + filename[0].replace("\\", "/") + ".xhtml\">" + hescape(title) + "</a></li>\n")
f.write("</ol>\n</nav>\n</body>\n</html>")
f.close()
@@ -278,7 +276,7 @@ def buildOPF(dstdir, title, filelist, cover=None):
"xmlns=\"http://www.idpf.org/2007/opf\">\n",
"<metadata xmlns:opf=\"http://www.idpf.org/2007/opf\" ",
"xmlns:dc=\"http://purl.org/dc/elements/1.1/\">\n",
"<dc:title>", title, "</dc:title>\n",
"<dc:title>", hescape(title), "</dc:title>\n",
"<dc:language>en-US</dc:language>\n",
"<dc:identifier id=\"BookID\">urn:uuid:", options.uuid, "</dc:identifier>\n",
"<dc:contributor id=\"contributor\">KindleComicConverter-" + __version__ + "</dc:contributor>\n"])
@@ -597,16 +595,12 @@ def getWorkFolder(afile):
raise UserWarning("Failed to extract images from PDF file.")
else:
workdir = mkdtemp('', 'KCC-')
cbx = cbxarchive.CBxArchive(afile)
if cbx.isCbxFile():
try:
path = cbx.extract(workdir)
except Exception:
rmtree(workdir, True)
raise UserWarning("Failed to extract archive.")
else:
try:
cbx = comicarchive.ComicArchive(afile)
path = cbx.extract(workdir)
except OSError as e:
rmtree(workdir, True)
raise UserWarning("Failed to detect archive format.")
raise UserWarning(e.strerror)
else:
raise UserWarning("Failed to open source file/directory.")
sanitizePermissions(path)
@@ -652,7 +646,6 @@ def getOutputFilename(srcpath, wantedname, ext, tomenumber):
def getComicInfo(path, originalpath):
xmlPath = os.path.join(path, 'ComicInfo.xml')
options.authors = ['KCC']
options.remoteCovers = {}
options.chapters = []
options.summary = ''
titleSuffix = ''
@@ -673,7 +666,7 @@ def getComicInfo(path, originalpath):
options.authors = []
if defaultTitle:
if xml.data['Series']:
options.title = escape(xml.data['Series'])
options.title = hescape(xml.data['Series'])
if xml.data['Volume']:
titleSuffix += ' V' + xml.data['Volume'].zfill(2)
if xml.data['Number']:
@@ -681,35 +674,19 @@ def getComicInfo(path, originalpath):
options.title += titleSuffix
for field in ['Writers', 'Pencillers', 'Inkers', 'Colorists']:
for person in xml.data[field]:
options.authors.append(escape(person))
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['MUid']:
options.remoteCovers = getCoversFromMCB(xml.data['MUid'])
if xml.data['Bookmarks']:
options.chapters = xml.data['Bookmarks']
if xml.data['Summary']:
options.summary = escape(xml.data['Summary'])
options.summary = hescape(xml.data['Summary'])
os.remove(xmlPath)
def getCoversFromMCB(mangaid):
covers = {}
try:
jsonRaw = urlopen(Request('http://mcd.iosphe.re/api/v1/series/' + mangaid + '/',
headers={'User-Agent': 'KindleComicConverter/' + __version__}))
jsonData = loads(jsonRaw.read().decode('utf-8'))
for volume in jsonData['Covers']['a']:
if volume['Side'] == 'front':
covers[int(volume['Volume'])] = volume['Raw']
except Exception:
return {}
return covers
def getDirectorySize(start_path='.'):
total_size = 0
for dirpath, _, filenames in os.walk(start_path):
@@ -790,7 +767,8 @@ def splitDirectory(path):
level = -1
for root, _, files in os.walk(os.path.join(path, 'OEBPS', 'Images')):
for f in files:
if f.endswith('.jpg') or f.endswith('.jpeg') or f.endswith('.png') or f.endswith('.gif'):
if f.endswith('.jpg') or f.endswith('.jpeg') or f.endswith('.png') or f.endswith('.gif') or \
f.endswith('.webp'):
newLevel = os.path.join(root, f).replace(os.path.join(path, 'OEBPS', 'Images'), '').count(os.sep)
if level != -1 and level != newLevel:
level = 0
@@ -872,7 +850,7 @@ def detectCorruption(tmppath, orgpath):
if 'decoder' in str(err) and 'not available' in str(err):
raise RuntimeError('Pillow was compiled without JPG and/or PNG decoder.')
else:
raise RuntimeError('Image file %s is corrupted.' % pathOrg)
raise RuntimeError('Image file %s is corrupted. Error: %s' % (pathOrg, str(err)))
else:
os.remove(os.path.join(root, name))
if alreadyProcessed:
@@ -932,7 +910,7 @@ def makeParser():
mainOptions.add_option("-p", "--profile", action="store", dest="profile", default="KV",
help="Device profile (Available options: K1, K2, K34, K578, KDX, KPW, KV, KO, KoMT, KoG,"
" KoGHD, KoA, KoAHD, KoAH2O, KoAO) [Default=KV]")
" KoGHD, KoA, KoAHD, KoAH2O, KoAO, KoF) [Default=KV]")
mainOptions.add_option("-m", "--manga-style", action="store_true", dest="righttoleft", default=False,
help="Manga style (right-to-left reading and splitting)")
mainOptions.add_option("-q", "--hq", action="store_true", dest="hq", default=False,
@@ -1053,21 +1031,17 @@ def checkOptions():
def checkTools(source):
source = source.upper()
if source.endswith('.CBR') or source.endswith('.RAR'):
rarExitCode = Popen('unrar', stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=True)
rarExitCode = rarExitCode.wait()
if rarExitCode != 0 and rarExitCode != 1 and rarExitCode != 7:
print('ERROR: UnRAR is missing!')
exit(1)
elif source.endswith('.CB7') or source.endswith('.7Z'):
sevenzaExitCode = Popen('7za', stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=True)
sevenzaExitCode = sevenzaExitCode.wait()
if sevenzaExitCode != 0 and sevenzaExitCode != 7:
print('ERROR: 7za is missing!')
if source.endswith('.CB7') or source.endswith('.7Z') or source.endswith('.RAR') or source.endswith('.CBR') or \
source.endswith('.ZIP') or source.endswith('.CBZ'):
process = Popen('7z', stdout=PIPE, stderr=STDOUT, shell=True)
process.communicate()
if process.returncode != 0 and process.returncode != 7:
print('ERROR: 7z is missing!')
exit(1)
if options.format == 'MOBI':
kindleGenExitCode = Popen('kindlegen -locale en', stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=True)
if kindleGenExitCode.wait() != 0:
kindleGenExitCode = Popen('kindlegen -locale en', stdout=PIPE, stderr=STDOUT, shell=True)
kindleGenExitCode.communicate()
if kindleGenExitCode.returncode != 0:
print('ERROR: KindleGen is missing!')
exit(1)
@@ -1214,7 +1188,7 @@ def makeMOBIWorker(item):
try:
if os.path.getsize(item) < 629145600:
output = Popen('kindlegen -dont_append_source -locale en "' + item + '"',
stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=True)
stdout=PIPE, stderr=STDOUT, shell=True)
for line in output.stdout:
line = line.decode('utf-8')
# ERROR: Generic error

View File

@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
# Copyright (c) 2013-2018 Pawel Jastrzebski <pawelj@iosphe.re>
# Copyright (c) 2013-2019 Pawel Jastrzebski <pawelj@iosphe.re>
#
# Permission to use, copy, modify, and/or distribute this software for
# any purpose with or without fee is hereby granted, provided that the

View File

@@ -0,0 +1,81 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
# Copyright (c) 2013-2019 Pawel Jastrzebski <pawelj@iosphe.re>
#
# Permission to use, copy, modify, and/or distribute this software for
# any purpose with or without fee is hereby granted, provided that the
# above copyright notice and this permission notice appear in all
# copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
# WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
# AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
# DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
# OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
#
import os
from psutil import Popen
from shutil import move
from subprocess import STDOUT, PIPE
from xml.dom.minidom import parseString
from xml.parsers.expat import ExpatError
class ComicArchive:
def __init__(self, filepath):
self.filepath = filepath
self.type = None
if not os.path.isfile(self.filepath):
raise OSError('File not found.')
process = Popen('7z l -y -p1 "' + self.filepath + '"', stderr=STDOUT, stdout=PIPE, shell=True)
for line in process.stdout:
if b'Type =' in line:
self.type = line.rstrip().decode().split(' = ')[1].upper()
break
process.communicate()
if process.returncode != 0:
raise OSError('Archive is corrupted or encrypted.')
elif self.type not in ['7Z', 'RAR', 'RAR5', 'ZIP']:
raise OSError('Unsupported archive format.')
def extract(self, targetdir):
if not os.path.isdir(targetdir):
raise OSError('Target directory don\'t exist.')
process = Popen('7z x -y -xr!__MACOSX -xr!.DS_Store -xr!thumbs.db -xr!Thumbs.db -o"' + targetdir + '" "' +
self.filepath + '"', stdout=PIPE, stderr=STDOUT, shell=True)
process.communicate()
if process.returncode != 0:
raise OSError('Failed to extract archive.')
tdir = os.listdir(targetdir)
if 'ComicInfo.xml' in tdir:
tdir.remove('ComicInfo.xml')
if len(tdir) == 1 and os.path.isdir(os.path.join(targetdir, tdir[0])):
for f in os.listdir(os.path.join(targetdir, tdir[0])):
move(os.path.join(targetdir, tdir[0], f), targetdir)
os.rmdir(os.path.join(targetdir, tdir[0]))
return targetdir
def addFile(self, sourcefile):
if self.type in ['RAR', 'RAR5']:
raise NotImplementedError
process = Popen('7z a -y "' + self.filepath + '" "' + sourcefile + '"',
stdout=PIPE, stderr=STDOUT, shell=True)
process.communicate()
if process.returncode != 0:
raise OSError('Failed to add the file.')
def extractMetadata(self):
process = Popen('7z x -y -so "' + self.filepath + '" ComicInfo.xml',
stdout=PIPE, stderr=STDOUT, shell=True)
xml = process.communicate()
if process.returncode != 0:
raise OSError('Failed to extract archive.')
try:
return parseString(xml[0])
except ExpatError:
return None

View File

@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
#
# Based on initial version of DualMetaFix. Copyright (C) 2013 Kevin Hendricks
# Changes for KCC Copyright (C) 2014-2018 Pawel Jastrzebski <pawelj@iosphe.re>
# Changes for KCC Copyright (C) 2014-2019 Pawel Jastrzebski <pawelj@iosphe.re>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -24,6 +24,7 @@ import shutil
class DualMetaFixException(Exception):
pass
# palm database offset constants
number_of_pdb_records = 76
first_pdb_record = 78

View File

@@ -4,7 +4,7 @@
# Copyright (C) 2011 Stanislav (proDOOMman) Kosolapov <prodoomman@gmail.com>
# Copyright (c) 2016 Alberto Planas <aplanas@gmail.com>
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
# Copyright (c) 2013-2018 Pawel Jastrzebski <pawelj@iosphe.re>
# Copyright (c) 2013-2019 Pawel Jastrzebski <pawelj@iosphe.re>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -20,12 +20,8 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
from io import BytesIO
from urllib.request import Request, urlopen
from urllib.parse import quote
from PIL import Image, ImageOps, ImageStat, ImageChops, ImageFilter
from .shared import md5Checksum
from . import __version__
class ProfileData:
@@ -86,7 +82,7 @@ class ProfileData:
'K578': ("Kindle", (600, 800), Palette16, 1.8),
'KDX': ("Kindle DX/DXG", (824, 1000), Palette16, 1.8),
'KPW': ("Kindle Paperwhite 1/2", (758, 1024), Palette16, 1.8),
'KV': ("Kindle Paperwhite 3/Voyage/Oasis", (1072, 1448), Palette16, 1.8),
'KV': ("Kindle Paperwhite 3/4/Voyage/Oasis", (1072, 1448), Palette16, 1.8),
'KO': ("Kindle Oasis 2", (1264, 1680), Palette16, 1.8),
'KoMT': ("Kobo Mini/Touch", (600, 800), Palette16, 1.8),
'KoG': ("Kobo Glo", (768, 1024), Palette16, 1.8),
@@ -95,12 +91,14 @@ class ProfileData:
'KoAHD': ("Kobo Aura HD", (1080, 1440), Palette16, 1.8),
'KoAH2O': ("Kobo Aura H2O", (1080, 1430), Palette16, 1.8),
'KoAO': ("Kobo Aura ONE", (1404, 1872), Palette16, 1.8),
'KoF': ("Kobo Forma", (1440, 1920), Palette16, 1.8),
'OTHER': ("Other", (0, 0), Palette16, 1.8),
}
class ComicPageParser:
def __init__(self, source, options):
Image.MAX_IMAGE_PIXELS = int(2048 * 2048 * 2048 // 4 // 3)
self.opt = options
self.source = source
self.size = self.opt.profileData[1]
@@ -345,15 +343,7 @@ class Cover:
self.tomeid = 1
else:
self.tomeid = tomeid
if self.tomeid in self.options.remoteCovers:
try:
source = urlopen(Request(quote(self.options.remoteCovers[self.tomeid]).replace('%3A', ':', 1),
headers={'User-Agent': 'KindleComicConverter/' + __version__})).read()
self.image = Image.open(BytesIO(source))
except Exception:
self.image = Image.open(source)
else:
self.image = Image.open(source)
self.image = Image.open(source)
self.process()
def process(self):

View File

@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2013-2018 Pawel Jastrzebski <pawelj@iosphe.re>
# Copyright (c) 2013-2019 Pawel Jastrzebski <pawelj@iosphe.re>
#
# Permission to use, copy, modify, and/or distribute this software for
# any purpose with or without fee is hereby granted, provided that the

View File

@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2013-2018 Pawel Jastrzebski <pawelj@iosphe.re>
# Copyright (c) 2013-2019 Pawel Jastrzebski <pawelj@iosphe.re>
#
# Permission to use, copy, modify, and/or distribute this software for
# any purpose with or without fee is hereby granted, provided that the
@@ -18,14 +18,9 @@
import os
from xml.dom.minidom import parse, Document
from re import compile
from zipfile import is_zipfile, ZipFile, ZIP_DEFLATED
from subprocess import STDOUT, PIPE
from psutil import Popen
from tempfile import mkdtemp
from shutil import rmtree
from .shared import removeFromZIP, check7ZFile as is_7zfile
from . import rarfile
from . import comicarchive
class MetadataParser:
@@ -39,50 +34,20 @@ class MetadataParser:
'Inkers': [],
'Colorists': [],
'Summary': '',
'MUid': '',
'Bookmarks': []}
self.rawdata = None
self.compressor = None
self.format = None
if self.source.endswith('.xml') and os.path.exists(self.source):
self.rawdata = parse(self.source)
self.parseXML()
elif not self.source.endswith('.xml'):
if is_zipfile(self.source):
self.compressor = 'zip'
with ZipFile(self.source) as zip_file:
for member in zip_file.namelist():
if member != 'ComicInfo.xml':
continue
with zip_file.open(member) as xml_file:
self.rawdata = parse(xml_file)
elif rarfile.is_rarfile(self.source):
self.compressor = 'rar'
with rarfile.RarFile(self.source) as rar_file:
for member in rar_file.namelist():
if member != 'ComicInfo.xml':
continue
with rar_file.open(member) as xml_file:
self.rawdata = parse(xml_file)
elif is_7zfile(self.source):
self.compressor = '7z'
workdir = mkdtemp('', 'KCC-')
tmpXML = os.path.join(workdir, 'ComicInfo.xml')
output = Popen('7za e "' + self.source + '" ComicInfo.xml -o"' + workdir + '"',
stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=True)
extracted = False
for line in output.stdout:
if b"Everything is Ok" in line or b"No files to process" in line:
extracted = True
if not extracted:
rmtree(workdir)
raise OSError('Failed to extract 7ZIP file.')
if os.path.isfile(tmpXML):
self.rawdata = parse(tmpXML)
rmtree(workdir)
else:
raise OSError('Failed to detect archive format.')
if self.rawdata:
self.parseXML()
try:
cbx = comicarchive.ComicArchive(self.source)
self.rawdata = cbx.extractMetadata()
self.format = cbx.type
except OSError as e:
raise UserWarning(e.strerror)
if self.rawdata:
self.parseXML()
def parseXML(self):
if len(self.rawdata.getElementsByTagName('Series')) != 0:
@@ -99,11 +64,6 @@ class MetadataParser:
self.data[field + 's'].append(person)
self.data[field + 's'] = list(set(self.data[field + 's']))
self.data[field + 's'].sort()
if len(self.rawdata.getElementsByTagName('ScanInformation')) != 0:
coverId = compile('(MCD\\()(\\d+)(\\))')\
.search(self.rawdata.getElementsByTagName('ScanInformation')[0].firstChild.nodeValue)
if coverId:
self.data['MUid'] = coverId.group(2)
if len(self.rawdata.getElementsByTagName('Page')) != 0:
for page in self.rawdata.getElementsByTagName('Page'):
if 'Bookmark' in page.attributes and 'Image' in page.attributes:
@@ -116,8 +76,7 @@ class MetadataParser:
for row in (['Series', self.data['Series']], ['Volume', self.data['Volume']],
['Number', self.data['Number']], ['Writer', ', '.join(self.data['Writers'])],
['Penciller', ', '.join(self.data['Pencillers'])], ['Inker', ', '.join(self.data['Inkers'])],
['Colorist', ', '.join(self.data['Colorists'])], ['Summary', self.data['Summary']],
['ScanInformation', 'MCD(' + self.data['MUid'] + ')' if self.data['MUid'] else '']):
['Colorist', ', '.join(self.data['Colorists'])], ['Summary', self.data['Summary']]):
if self.rawdata.getElementsByTagName(row[0]):
node = self.rawdata.getElementsByTagName(row[0])[0]
if row[1]:
@@ -138,8 +97,7 @@ class MetadataParser:
for row in (['Series', self.data['Series']], ['Volume', self.data['Volume']],
['Number', self.data['Number']], ['Writer', ', '.join(self.data['Writers'])],
['Penciller', ', '.join(self.data['Pencillers'])], ['Inker', ', '.join(self.data['Inkers'])],
['Colorist', ', '.join(self.data['Colorists'])], ['Summary', self.data['Summary']],
['ScanInformation', 'MCD(' + self.data['MUid'] + ')' if self.data['MUid'] else '']):
['Colorist', ', '.join(self.data['Colorists'])], ['Summary', self.data['Summary']]):
if row[1]:
main = doc.createElement(row[0])
root.appendChild(main)
@@ -154,20 +112,9 @@ class MetadataParser:
tmpXML = os.path.join(workdir, 'ComicInfo.xml')
with open(tmpXML, 'w', encoding='utf-8') as f:
self.rawdata.writexml(f, encoding='utf-8')
if is_zipfile(self.source):
removeFromZIP(self.source, 'ComicInfo.xml')
with ZipFile(self.source, mode='a', compression=ZIP_DEFLATED) as zip_file:
zip_file.write(tmpXML, arcname=tmpXML.split(os.sep)[-1])
elif rarfile.is_rarfile(self.source):
raise NotImplementedError
elif is_7zfile(self.source):
output = Popen('7za a "' + self.source + '" "' + tmpXML + '"',
stdout=PIPE, stderr=STDOUT, stdin=PIPE, shell=True)
extracted = False
for line in output.stdout:
if b"Everything is Ok" in line:
extracted = True
if not extracted:
rmtree(workdir)
raise OSError('Failed to modify 7ZIP file.')
try:
cbx = comicarchive.ComicArchive(self.source)
cbx.addFile(tmpXML)
except OSError as e:
raise UserWarning(e.strerror)
rmtree(workdir)

View File

@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
# Copyright (c) 2013-2018 Pawel Jastrzebski <pawelj@iosphe.re>
# Copyright (c) 2013-2019 Pawel Jastrzebski <pawelj@iosphe.re>
#
# Based upon the code snippet by Ned Batchelder
# (http://nedbatchelder.com/blog/200712/extracting_jpgs_from_pdfs.html)

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
# Copyright (c) 2013-2018 Pawel Jastrzebski <pawelj@iosphe.re>
# Copyright (c) 2013-2019 Pawel Jastrzebski <pawelj@iosphe.re>
#
# Permission to use, copy, modify, and/or distribute this software for
# any purpose with or without fee is hereby granted, provided that the
@@ -22,9 +22,6 @@ import os
from hashlib import md5
from html.parser import HTMLParser
from distutils.version import StrictVersion
from shutil import rmtree, copy
from tempfile import mkdtemp
from zipfile import ZipFile, ZIP_DEFLATED
from re import split
from traceback import format_tb
@@ -50,7 +47,7 @@ class HTMLStripper(HTMLParser):
def getImageFileName(imgfile):
name, ext = os.path.splitext(imgfile)
ext = ext.lower()
if name.startswith('.') or (ext != '.png' and ext != '.jpg' and ext != '.jpeg' and ext != '.gif'):
if name.startswith('.') or ext not in ['.png', '.jpg', '.jpeg', '.gif', '.webp']:
return None
return [name, ext]
@@ -86,38 +83,19 @@ def md5Checksum(fpath):
return m.hexdigest()
def check7ZFile(fpath):
with open(fpath, 'rb') as fh:
header = fh.read(6)
return header == b"7z\xbc\xaf'\x1c"
def removeFromZIP(zipfname, *filenames):
tempdir = mkdtemp('', 'KCC-')
try:
tempname = os.path.join(tempdir, 'KCC.zip')
with ZipFile(zipfname, 'r') as zipread:
with ZipFile(tempname, 'w', compression=ZIP_DEFLATED) as zipwrite:
for item in zipread.infolist():
if item.filename not in filenames:
zipwrite.writestr(item, zipread.read(item.filename))
copy(tempname, zipfname)
finally:
rmtree(tempdir, True)
def sanitizeTrace(traceback):
return ''.join(format_tb(traceback))\
.replace('C:/projects/kcc/', '') \
.replace('c:/projects/kcc/', '') \
.replace('C:/projects/kcc/', '')\
.replace('c:/projects/kcc/', '')\
.replace('C:/python36-x64/', '')\
.replace('c:/python36-x64/', '')\
.replace('C:\\projects\\kcc\\', '') \
.replace('c:\\projects\\kcc\\', '') \
.replace('C:\\projects\\kcc\\', '')\
.replace('c:\\projects\\kcc\\', '')\
.replace('C:\\python36-x64\\', '')\
.replace('c:\\python36-x64\\', '')
# noinspection PyUnresolvedReferences
def dependencyCheck(level):
missing = []
if level > 2:
@@ -145,11 +123,11 @@ def dependencyCheck(level):
except ImportError:
missing.append('python-slugify 1.2.1+')
try:
from PIL import PILLOW_VERSION as pillowVersion
if StrictVersion('4.0.0') > StrictVersion(pillowVersion):
missing.append('Pillow 4.0.0+')
from PIL import __version__ as pillowVersion
if StrictVersion('5.2.0') > StrictVersion(pillowVersion):
missing.append('Pillow 5.2.0+')
except ImportError:
missing.append('Pillow 4.0.0+')
missing.append('Pillow 5.2.0+')
if len(missing) > 0:
print('ERROR: ' + ', '.join(missing) + ' is not installed!')
exit(1)

View File

@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
# Copyright (c) 2013-2018 Pawel Jastrzebski <pawelj@iosphe.re>
# Copyright (c) 2013-2019 Pawel Jastrzebski <pawelj@iosphe.re>
#
# Permission to use, copy, modify, and/or distribute this software for
# any purpose with or without fee is hereby granted, provided that the
@@ -30,15 +30,15 @@ def start():
os.environ['QT_AUTO_SCREEN_SCALE_FACTOR'] = "1"
KCCAplication = KCC_gui.QApplicationMessaging(sys.argv)
if KCCAplication.isRunning():
if len(sys.argv) > 1:
KCCAplication.sendMessage(sys.argv[1])
for i in range(1, len(sys.argv)):
KCCAplication.sendMessage(sys.argv[i])
else:
KCCAplication.sendMessage('ARISE')
else:
KCCWindow = KCC_gui.QMainWindowKCC()
KCCUI = KCC_gui.KCCGUI(KCCAplication, KCCWindow)
if len(sys.argv) > 1:
KCCUI.handleMessage(sys.argv[1])
for i in range(1, len(sys.argv)):
KCCUI.handleMessage(sys.argv[i])
sys.exit(KCCAplication.exec_())

View File

@@ -1,4 +0,0 @@
kindlecomicconverter: binary-without-manpage usr/bin/kcc
kindlecomicconverter: wrong-name-for-changelog-of-native-package usr/share/doc/kindlecomicconverter/changelog.Debian.gz
kindlecomicconverter: file-missing-in-md5sums usr/share/doc/kindlecomicconverter/changelog.Debian.gz
kindlecomicconverter: hardening-no-relro usr/bin/kcc

View File

@@ -1,11 +0,0 @@
[Desktop Entry]
Type=Application
Version=1.0
Name=Kindle Comic Converter
GenericName=Kindle Comic Converter
Comment=Comic and Manga converter for e-book readers
Icon=/usr/share/kindlecomicconverter/comic2ebook.png
Exec=/usr/bin/kcc %f
Terminal=false
Categories=Graphics;
MimeType=application/zip;application/x-rar;application/x-7z-compressed;

Binary file not shown.

BIN
other/osx/7z Normal file

Binary file not shown.

BIN
other/osx/7z.so Normal file

Binary file not shown.

Binary file not shown.

View File

@@ -30,7 +30,7 @@
<key>CFBundleExecutable</key>
<string>MacOS/Kindle Comic Converter</string>
<key>CFBundleGetInfoString</key>
<string>KindleComicConverter 5.4.5, written 2012-2018 by Ciro Mattia Gonano and Pawel Jastrzebski</string>
<string>KindleComicConverter 5.5.0, written 2012-2019 by Ciro Mattia Gonano and Pawel Jastrzebski</string>
<key>CFBundleIconFile</key>
<string>comic2ebook.icns</string>
<key>CFBundleIdentifier</key>
@@ -42,11 +42,11 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>5.4.5</string>
<string>5.5.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>5.4.5</string>
<string>5.5.0</string>
<key>LSEnvironment</key>
<dict>
<key>PATH</key>
@@ -55,7 +55,7 @@
<key>LSHasLocalizedDisplayName</key>
<false/>
<key>LSMinimumSystemVersion</key>
<string>10.10.0</string>
<string>10.12.0</string>
<key>NSAppleScriptEnabled</key>
<false/>
<key>NSHumanReadableCopyright</key>

Binary file not shown.

BIN
other/windows/7z.dll Normal file

Binary file not shown.

BIN
other/windows/7z.exe Normal file

Binary file not shown.

Binary file not shown.

View File

@@ -1,56 +1,22 @@
****** ***** ****** UnRAR - free utility for RAR archives
** ** ** ** ** ** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
****** ******* ****** License for use and distribution of
** ** ** ** ** ** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
** ** ** ** ** ** FREEWARE version
~~~~~~~~~~~~~~~~
The UnRAR utility is freeware. This means:
1. All copyrights to RAR and the utility UnRAR are exclusively
owned by the author - Alexander Roshal.
2. The UnRAR utility may be freely distributed. It is allowed
to distribute UnRAR inside of other software packages.
3. THE RAR ARCHIVER AND THE UnRAR UTILITY ARE DISTRIBUTED "AS IS".
NO WARRANTY OF ANY KIND IS EXPRESSED OR IMPLIED. YOU USE AT
YOUR OWN RISK. THE AUTHOR WILL NOT BE LIABLE FOR DATA LOSS,
DAMAGES, LOSS OF PROFITS OR ANY OTHER KIND OF LOSS WHILE USING
OR MISUSING THIS SOFTWARE.
4. Neither RAR binary code, WinRAR binary code, UnRAR source or UnRAR
binary code may be used or reverse engineered to re-create the RAR
compression algorithm, which is proprietary, without written
permission of the author.
5. If you don't agree with terms of the license you must remove
UnRAR files from your storage devices and cease to use the
utility.
Thank you for your interest in RAR and UnRAR.
Alexander L. Roshal
7-Zip
~~~~~
License for use and distribution
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7-Zip Copyright (C) 1999-2012 Igor Pavlov.
7-Zip Copyright (C) 1999-2018 Igor Pavlov.
Licenses for files are:
The licenses for files are:
1) 7z.dll: GNU LGPL + unRAR restriction
2) All other files: GNU LGPL
1) 7z.dll:
- The "GNU LGPL" as main license for most of the code
- The "GNU LGPL" with "unRAR license restriction" for some code
- The "BSD 3-clause License" for some code
2) All other files: the "GNU LGPL".
The GNU LGPL + unRAR restriction means that you must follow both
GNU LGPL rules and unRAR restriction rules.
Redistributions in binary form must reproduce related license information from this file.
Note:
You can use 7-Zip on any computer, including a computer in a commercial
Note:
You can use 7-Zip on any computer, including a computer in a commercial
organization. You don't need to register or pay for 7-Zip.
@@ -67,21 +33,54 @@
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You can receive a copy of the GNU Lesser General Public License from
You can receive a copy of the GNU Lesser General Public License from
http://www.gnu.org/
unRAR restriction
-----------------
The decompression engine for RAR archives was developed using source
BSD 3-clause License
--------------------
The "BSD 3-clause License" is used for the code in 7z.dll that implements LZFSE data decompression.
That code was derived from the code in the "LZFSE compression library" developed by Apple Inc,
that also uses the "BSD 3-clause License":
----
Copyright (c) 2015-2016, Apple Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder(s) nor the names of any contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----
unRAR license restriction
-------------------------
The decompression engine for RAR archives was developed using source
code of unRAR program.
All copyrights to original unRAR code are owned by Alexander Roshal.
The license for original unRAR code has the following restriction:
The unRAR sources cannot be used to re-create the RAR compression algorithm,
which is proprietary. Distribution of modified unRAR sources in separate form
The unRAR sources cannot be used to re-create the RAR compression algorithm,
which is proprietary. Distribution of modified unRAR sources in separate form
or as a part of other software is permitted, provided that it is clearly
stated in the documentation and source comments that the code may
not be used to develop a RAR (WinRAR) compatible archiver.

Binary file not shown.

View File

@@ -1,5 +1,5 @@
PyQt5>=5.6.0
Pillow>=4.0.0
Pillow>=5.2.0
psutil>=5.0.0
python-slugify>=1.2.1
python-slugify>=1.2.1,<3.0.0
raven>=6.0.0

View File

@@ -6,7 +6,7 @@ pip/pyinstaller build script for KCC.
Install as Python package:
python3 setup.py install
Create EXE/APP/DEB:
Create EXE/APP:
python3 setup.py build_binary
"""
@@ -37,35 +37,18 @@ class BuildBinaryCommand(distutils.cmd.Command):
VERSION = __version__
if sys.platform == 'darwin':
os.system('pyinstaller -y -F -i icons/comic2ebook.icns -n "Kindle Comic Converter" -w -s kcc.py')
shutil.copy('other/osx/7za', 'dist/Kindle Comic Converter.app/Contents/Resources')
shutil.copy('other/osx/unrar', 'dist/Kindle Comic Converter.app/Contents/Resources')
shutil.copy('other/osx/7z', 'dist/Kindle Comic Converter.app/Contents/Resources')
shutil.copy('other/osx/7z.so', 'dist/Kindle Comic Converter.app/Contents/Resources')
shutil.copy('other/osx/Info.plist', 'dist/Kindle Comic Converter.app/Contents')
shutil.copy('LICENSE.txt', 'dist/Kindle Comic Converter.app/Contents/Resources')
shutil.copy('other/windows/Additional-LICENSE.txt', 'dist/Kindle Comic Converter.app/Contents/Resources')
os.chmod('dist/Kindle Comic Converter.app/Contents/Resources/unrar', 0o777)
os.chmod('dist/Kindle Comic Converter.app/Contents/Resources/7za', 0o777)
os.chmod('dist/Kindle Comic Converter.app/Contents/Resources/7z', 0o777)
os.system('appdmg kcc.json dist/KindleComicConverter_osx_' + VERSION + '.dmg')
exit(0)
elif sys.platform == 'win32':
os.system('pyinstaller -y -F -i icons\comic2ebook.ico -n KCC -w --noupx kcc.py')
os.system('pyinstaller -y -F -i icons\\comic2ebook.ico -n KCC -w --noupx kcc.py')
exit(0)
else:
os.system('pyinstaller -y -F kcc.py')
os.system('mkdir -p dist/usr/bin dist/usr/share/applications dist/usr/share/doc/kindlecomicconverter '
'dist/usr/share/kindlecomicconverter dist/usr/share/lintian/overrides')
os.system('mv dist/kcc dist/usr/bin')
os.system('cp icons/comic2ebook.png dist/usr/share/kindlecomicconverter')
os.system('cp LICENSE.txt dist/usr/share/doc/kindlecomicconverter/copyright')
os.system('cp other/linux/kindlecomicconverter.desktop dist/usr/share/applications')
os.system('cp other/linux/kindlecomicconverter dist/usr/share/lintian/overrides')
os.chdir('dist')
os.system('fpm -f -s dir -t deb -n kindlecomicconverter -v ' + VERSION +
' -m "Pawel Jastrzebski <pawelj@iosphe.re>" --license "ISC" '
'--description "$(printf "Comic and Manga converter for e-book '
'readers.\nThis app allows you to transform your PNG, JPG, GIF, '
'CBZ, CBR and CB7 files\ninto EPUB or MOBI format e-books.")" '
'--url "https://kcc.iosphe.re/" --deb-priority "optional" --vendor "" '
'--category "graphics" -d "unrar | unrar-free" -d "p7zip-full" -d "libc6" usr')
exit(0)
@@ -93,7 +76,7 @@ setuptools.setup(
packages=['kindlecomicconverter'],
install_requires=[
'PyQt5>=5.6.0',
'Pillow>=4.0.0',
'Pillow>=5.2.0',
'psutil>=5.0.0',
'python-slugify>=1.2.1',
'raven>=6.0.0',