mirror of
https://github.com/ciromattia/kcc
synced 2025-12-16 03:06:33 +00:00
Version 4.0 - first draft for Python3 conversion
This commit is contained in:
2
kcc.iss
2
kcc.iss
@@ -1,5 +1,5 @@
|
|||||||
#define MyAppName "Kindle Comic Converter"
|
#define MyAppName "Kindle Comic Converter"
|
||||||
#define MyAppVersion "3.6"
|
#define MyAppVersion "4.0"
|
||||||
#define MyAppPublisher "Ciro Mattia Gonano, Paweł Jastrzębski"
|
#define MyAppPublisher "Ciro Mattia Gonano, Paweł Jastrzębski"
|
||||||
#define MyAppURL "http://kcc.vulturis.eu/"
|
#define MyAppURL "http://kcc.vulturis.eu/"
|
||||||
#define MyAppExeName "KCC.exe"
|
#define MyAppExeName "KCC.exe"
|
||||||
|
|||||||
12
kcc.py
12
kcc.py
@@ -18,7 +18,7 @@
|
|||||||
# 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.
|
||||||
|
|
||||||
__version__ = '3.6'
|
__version__ = '4.0'
|
||||||
__license__ = 'ISC'
|
__license__ = 'ISC'
|
||||||
__copyright__ = '2012-2013, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@vulturis.eu>'
|
__copyright__ = '2012-2013, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@vulturis.eu>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
@@ -29,13 +29,13 @@ try:
|
|||||||
#noinspection PyUnresolvedReferences
|
#noinspection PyUnresolvedReferences
|
||||||
from PyQt4 import QtCore, QtGui, QtNetwork
|
from PyQt4 import QtCore, QtGui, QtNetwork
|
||||||
except ImportError:
|
except ImportError:
|
||||||
print "ERROR: PyQT4 is not installed!"
|
print("ERROR: PyQT4 is not installed!")
|
||||||
if sys.platform.startswith('linux'):
|
if sys.platform.startswith('linux'):
|
||||||
import Tkinter
|
import tkinter
|
||||||
import tkMessageBox
|
import tkinter.messagebox
|
||||||
importRoot = Tkinter.Tk()
|
importRoot = tkinter.Tk()
|
||||||
importRoot.withdraw()
|
importRoot.withdraw()
|
||||||
tkMessageBox.showerror("KCC - Error", "PyQT4 is not installed!")
|
tkinter.messagebox.showerror("KCC - Error", "PyQT4 is not installed!")
|
||||||
exit(1)
|
exit(1)
|
||||||
from kcc import KCC_gui
|
from kcc import KCC_gui
|
||||||
from multiprocessing import freeze_support
|
from multiprocessing import freeze_support
|
||||||
|
|||||||
181
kcc/KCC_gui.py
181
kcc/KCC_gui.py
@@ -17,7 +17,7 @@
|
|||||||
# 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.
|
||||||
|
|
||||||
__version__ = '3.6'
|
__version__ = '4.0'
|
||||||
__license__ = 'ISC'
|
__license__ = 'ISC'
|
||||||
__copyright__ = '2012-2013, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@vulturis.eu>'
|
__copyright__ = '2012-2013, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@vulturis.eu>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
@@ -25,39 +25,38 @@ __docformat__ = 'restructuredtext en'
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
import urllib2
|
import urllib.request, urllib.error, urllib.parse
|
||||||
import socket
|
import socket
|
||||||
import comic2ebook
|
from . import comic2ebook
|
||||||
import kindlesplit
|
from . import kindlesplit
|
||||||
from string import split
|
|
||||||
from time import sleep
|
from time import sleep
|
||||||
from shutil import move
|
from shutil import move
|
||||||
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
|
from http.server import BaseHTTPRequestHandler, HTTPServer
|
||||||
from SocketServer import ThreadingMixIn
|
from socketserver import ThreadingMixIn
|
||||||
from image import ProfileData
|
from .image import ProfileData
|
||||||
from subprocess import STDOUT, PIPE
|
from subprocess import STDOUT, PIPE
|
||||||
from PyQt4 import QtGui, QtCore
|
from PyQt4 import QtGui, QtCore
|
||||||
from xml.dom.minidom import parse
|
from xml.dom.minidom import parse
|
||||||
from HTMLParser import HTMLParser
|
from html.parser import HTMLParser
|
||||||
from KCC_rc_web import WebContent
|
from .KCC_rc_web import WebContent
|
||||||
try:
|
try:
|
||||||
#noinspection PyUnresolvedReferences
|
#noinspection PyUnresolvedReferences
|
||||||
from psutil import TOTAL_PHYMEM, Popen
|
from psutil import TOTAL_PHYMEM, Popen
|
||||||
except ImportError:
|
except ImportError:
|
||||||
print "ERROR: Psutil is not installed!"
|
print("ERROR: Psutil is not installed!")
|
||||||
if sys.platform.startswith('linux'):
|
if sys.platform.startswith('linux'):
|
||||||
import Tkinter
|
import tkinter
|
||||||
import tkMessageBox
|
import tkinter.messagebox
|
||||||
importRoot = Tkinter.Tk()
|
importRoot = tkinter.Tk()
|
||||||
importRoot.withdraw()
|
importRoot.withdraw()
|
||||||
tkMessageBox.showerror("KCC - Error", "Psutil is not installed!")
|
tkinter.messagebox.showerror("KCC - Error", "Psutil is not installed!")
|
||||||
exit(1)
|
exit(1)
|
||||||
if sys.platform.startswith('darwin'):
|
if sys.platform.startswith('darwin'):
|
||||||
import KCC_ui_osx as KCC_ui
|
from . import KCC_ui_osx as KCC_ui
|
||||||
elif sys.platform.startswith('linux'):
|
elif sys.platform.startswith('linux'):
|
||||||
import KCC_ui_linux as KCC_ui
|
from . import KCC_ui_linux as KCC_ui
|
||||||
else:
|
else:
|
||||||
import KCC_ui
|
from . import KCC_ui
|
||||||
|
|
||||||
|
|
||||||
class Icons:
|
class Icons:
|
||||||
@@ -130,8 +129,8 @@ class WebServerHandler(BaseHTTPRequestHandler):
|
|||||||
'<p style="font-size:50px">- <img style="vertical-align: middle" '
|
'<p style="font-size:50px">- <img style="vertical-align: middle" '
|
||||||
'alt="KCC Logo" src="' + GUI.webContent.logo + '" /> -</p>\n')
|
'alt="KCC Logo" src="' + GUI.webContent.logo + '" /> -</p>\n')
|
||||||
if len(GUI.completedWork) > 0 and not GUI.conversionAlive:
|
if len(GUI.completedWork) > 0 and not GUI.conversionAlive:
|
||||||
for key in sorted(GUI.completedWork.iterkeys()):
|
for key in sorted(GUI.completedWork.keys()):
|
||||||
self.wfile.write('<p><a href="' + key + '">' + split(key, '.')[0] + '</a></p>\n')
|
self.wfile.write('<p><a href="' + key + '">' + key.split('.')[0] + '</a></p>\n')
|
||||||
else:
|
else:
|
||||||
self.wfile.write('<p style="font-weight: bold">No downloads are available.<br/>'
|
self.wfile.write('<p style="font-weight: bold">No downloads are available.<br/>'
|
||||||
'Convert some files and refresh this page.</p>\n')
|
'Convert some files and refresh this page.</p>\n')
|
||||||
@@ -139,7 +138,7 @@ class WebServerHandler(BaseHTTPRequestHandler):
|
|||||||
'</body>\n'
|
'</body>\n'
|
||||||
'</html>\n')
|
'</html>\n')
|
||||||
elif sendReply:
|
elif sendReply:
|
||||||
outputFile = GUI.completedWork[urllib2.unquote(self.path[1:])].decode('utf-8')
|
outputFile = GUI.completedWork[urllib.parse.unquote(self.path[1:])].decode('utf-8')
|
||||||
fp = open(outputFile, 'rb')
|
fp = open(outputFile, 'rb')
|
||||||
self.send_response(200)
|
self.send_response(200)
|
||||||
self.send_header('Content-type', mimetype)
|
self.send_header('Content-type', mimetype)
|
||||||
@@ -173,7 +172,7 @@ class WebServerThread(QtCore.QThread):
|
|||||||
try:
|
try:
|
||||||
# Sweet cross-platform one-liner to get LAN ip address
|
# Sweet cross-platform one-liner to get LAN ip address
|
||||||
lIP = [ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith("127.")][:1][0]
|
lIP = [ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith("127.")][:1][0]
|
||||||
except StandardError:
|
except Exception:
|
||||||
# Sadly it can fail on some Linux configurations
|
# Sadly it can fail on some Linux configurations
|
||||||
lIP = None
|
lIP = None
|
||||||
try:
|
try:
|
||||||
@@ -186,7 +185,7 @@ class WebServerThread(QtCore.QThread):
|
|||||||
self.emit(QtCore.SIGNAL("addMessage"), '<b>Content server</b> started on port 4242.', 'info')
|
self.emit(QtCore.SIGNAL("addMessage"), '<b>Content server</b> started on port 4242.', 'info')
|
||||||
while self.running:
|
while self.running:
|
||||||
self.server.handle_request()
|
self.server.handle_request()
|
||||||
except StandardError:
|
except Exception:
|
||||||
self.emit(QtCore.SIGNAL("addMessage"), '<b>Content server</b> failed to start!', 'error')
|
self.emit(QtCore.SIGNAL("addMessage"), '<b>Content server</b> failed to start!', 'error')
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
@@ -202,9 +201,9 @@ class VersionThread(QtCore.QThread):
|
|||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
try:
|
try:
|
||||||
XML = urllib2.urlopen('http://kcc.vulturis.eu/Version.php')
|
XML = urllib.request.urlopen('http://kcc.vulturis.eu/Version.php')
|
||||||
XML = parse(XML)
|
XML = parse(XML)
|
||||||
except StandardError:
|
except Exception:
|
||||||
return
|
return
|
||||||
latestVersion = XML.childNodes[0].getElementsByTagName('latest')[0].childNodes[0].toxml()
|
latestVersion = XML.childNodes[0].getElementsByTagName('latest')[0].childNodes[0].toxml()
|
||||||
if tuple(map(int, (latestVersion.split(".")))) > tuple(map(int, (__version__.split(".")))):
|
if tuple(map(int, (latestVersion.split(".")))) > tuple(map(int, (__version__.split(".")))):
|
||||||
@@ -253,9 +252,10 @@ class KindleGenThread(QtCore.QRunnable):
|
|||||||
kindlegenError = ''
|
kindlegenError = ''
|
||||||
try:
|
try:
|
||||||
if os.path.getsize(self.work) < 367001600:
|
if os.path.getsize(self.work) < 367001600:
|
||||||
output = Popen('kindlegen -locale en "' + self.work.encode(sys.getfilesystemencoding()) + '"',
|
output = Popen('kindlegen -locale en "' + self.work.encode(sys.getfilesystemencoding()).decode('utf-8')
|
||||||
stdout=PIPE, stderr=STDOUT, shell=True)
|
+ '"', stdout=PIPE, stderr=STDOUT, shell=True)
|
||||||
for line in output.stdout:
|
for line in output.stdout:
|
||||||
|
line = line.decode('utf-8')
|
||||||
# ERROR: Generic error
|
# ERROR: Generic error
|
||||||
if "Error(" in line:
|
if "Error(" in line:
|
||||||
kindlegenErrorCode = 1
|
kindlegenErrorCode = 1
|
||||||
@@ -269,9 +269,10 @@ class KindleGenThread(QtCore.QRunnable):
|
|||||||
# ERROR: EPUB too big
|
# ERROR: EPUB too big
|
||||||
kindlegenErrorCode = 23026
|
kindlegenErrorCode = 23026
|
||||||
self.signals.result.emit([kindlegenErrorCode, kindlegenError, self.work])
|
self.signals.result.emit([kindlegenErrorCode, kindlegenError, self.work])
|
||||||
except StandardError:
|
except Exception as err:
|
||||||
# ERROR: Unknown generic error
|
# ERROR: KCC unknown generic error
|
||||||
kindlegenErrorCode = 1
|
kindlegenErrorCode = 1
|
||||||
|
kindlegenError = format(err)
|
||||||
self.signals.result.emit([kindlegenErrorCode, kindlegenError, self.work])
|
self.signals.result.emit([kindlegenErrorCode, kindlegenError, self.work])
|
||||||
|
|
||||||
|
|
||||||
@@ -297,8 +298,9 @@ class KindleUnpackThread(QtCore.QRunnable):
|
|||||||
mobisplit = kindlesplit.mobi_split(mobiPath + '_toclean', newKindle)
|
mobisplit = kindlesplit.mobi_split(mobiPath + '_toclean', newKindle)
|
||||||
open(mobiPath, 'wb').write(mobisplit.getResult())
|
open(mobiPath, 'wb').write(mobisplit.getResult())
|
||||||
self.signals.result.emit([True])
|
self.signals.result.emit([True])
|
||||||
except StandardError:
|
except Exception as err:
|
||||||
self.signals.result.emit([False])
|
traceback.print_exc()
|
||||||
|
self.signals.result.emit([False, format(err)])
|
||||||
|
|
||||||
|
|
||||||
class WorkerThread(QtCore.QThread):
|
class WorkerThread(QtCore.QThread):
|
||||||
@@ -385,7 +387,7 @@ class WorkerThread(QtCore.QThread):
|
|||||||
for i in range(GUI.JobList.count()):
|
for i in range(GUI.JobList.count()):
|
||||||
# Make sure that we don't consider any system message as job to do
|
# Make sure that we don't consider any system message as job to do
|
||||||
if GUI.JobList.item(i).icon().isNull():
|
if GUI.JobList.item(i).icon().isNull():
|
||||||
currentJobs.append(unicode(GUI.JobList.item(i).text()))
|
currentJobs.append(str(GUI.JobList.item(i).text()))
|
||||||
GUI.JobList.clear()
|
GUI.JobList.clear()
|
||||||
for job in currentJobs:
|
for job in currentJobs:
|
||||||
sleep(0.5)
|
sleep(0.5)
|
||||||
@@ -466,42 +468,45 @@ class WorkerThread(QtCore.QThread):
|
|||||||
if self.kindlegenErrorCode[0] == 0:
|
if self.kindlegenErrorCode[0] == 0:
|
||||||
GUI.progress.content = ''
|
GUI.progress.content = ''
|
||||||
self.emit(QtCore.SIGNAL("addMessage"), 'Creating MOBI files... <b>Done!</b>', 'info', True)
|
self.emit(QtCore.SIGNAL("addMessage"), 'Creating MOBI files... <b>Done!</b>', 'info', True)
|
||||||
self.emit(QtCore.SIGNAL("addMessage"), 'Cleaning MOBI files', 'info')
|
self.emit(QtCore.SIGNAL("addMessage"), 'Cleaning MOBI files is currently disabled in this branch', 'info')
|
||||||
GUI.progress.content = 'Cleaning MOBI files'
|
GUI.progress.content = 'Cleaning MOBI files is currently disabled in this branch'
|
||||||
self.workerOutput = []
|
#self.emit(QtCore.SIGNAL("addMessage"), 'Cleaning MOBI files', 'info')
|
||||||
# Multithreading KindleUnpack in current form is a waste of resources.
|
#GUI.progress.content = 'Cleaning MOBI files'
|
||||||
# Unless we higly optimise KindleUnpack or drop 32bit support this will not change.
|
#self.workerOutput = []
|
||||||
self.pool.setMaxThreadCount(1)
|
## Multithreading KindleUnpack in current form is a waste of resources.
|
||||||
for item in outputPath:
|
## Unless we higly optimise KindleUnpack or drop 32bit support this will not change.
|
||||||
worker = KindleUnpackThread([item, profile])
|
#self.pool.setMaxThreadCount(1)
|
||||||
worker.signals.result.connect(self.addResult)
|
#for item in outputPath:
|
||||||
self.pool.start(worker)
|
# worker = KindleUnpackThread([item, profile])
|
||||||
self.pool.waitForDone()
|
# worker.signals.result.connect(self.addResult)
|
||||||
sleep(0.5)
|
# self.pool.start(worker)
|
||||||
for success in self.workerOutput:
|
#self.pool.waitForDone()
|
||||||
if not success:
|
#sleep(0.5)
|
||||||
self.errors = True
|
#for success in self.workerOutput:
|
||||||
break
|
# if not success[0]:
|
||||||
if not self.errors:
|
# self.errors = True
|
||||||
for item in outputPath:
|
# print(success[1])
|
||||||
GUI.progress.content = ''
|
# break
|
||||||
mobiPath = item.replace('.epub', '.mobi')
|
#if not self.errors:
|
||||||
os.remove(mobiPath + '_toclean')
|
# for item in outputPath:
|
||||||
GUI.completedWork[os.path.basename(mobiPath).encode('utf-8')] = \
|
# GUI.progress.content = ''
|
||||||
mobiPath.encode('utf-8')
|
# mobiPath = item.replace('.epub', '.mobi')
|
||||||
self.emit(QtCore.SIGNAL("addMessage"), 'Cleaning MOBI files... <b>Done!</b>', 'info',
|
# os.remove(mobiPath + '_toclean')
|
||||||
True)
|
# GUI.completedWork[os.path.basename(mobiPath).encode('utf-8')] = \
|
||||||
else:
|
# mobiPath.encode('utf-8')
|
||||||
GUI.progress.content = ''
|
# self.emit(QtCore.SIGNAL("addMessage"), 'Cleaning MOBI files... <b>Done!</b>', 'info',
|
||||||
for item in outputPath:
|
# True)
|
||||||
mobiPath = item.replace('.epub', '.mobi')
|
#else:
|
||||||
if os.path.exists(mobiPath):
|
# GUI.progress.content = ''
|
||||||
os.remove(mobiPath)
|
# for item in outputPath:
|
||||||
if os.path.exists(mobiPath + '_toclean'):
|
# mobiPath = item.replace('.epub', '.mobi')
|
||||||
os.remove(mobiPath + '_toclean')
|
# if os.path.exists(mobiPath):
|
||||||
self.emit(QtCore.SIGNAL("addMessage"), 'KindleUnpack failed to clean MOBI file!', 'error')
|
# os.remove(mobiPath)
|
||||||
self.emit(QtCore.SIGNAL("addTrayMessage"), 'KindleUnpack failed to clean MOBI file!',
|
# if os.path.exists(mobiPath + '_toclean'):
|
||||||
'Critical')
|
# os.remove(mobiPath + '_toclean')
|
||||||
|
# self.emit(QtCore.SIGNAL("addMessage"), 'KindleUnpack failed to clean MOBI file!', 'error')
|
||||||
|
# self.emit(QtCore.SIGNAL("addTrayMessage"), 'KindleUnpack failed to clean MOBI file!',
|
||||||
|
# 'Critical')
|
||||||
else:
|
else:
|
||||||
GUI.progress.content = ''
|
GUI.progress.content = ''
|
||||||
epubSize = (os.path.getsize(self.kindlegenErrorCode[2]))/1024/1024
|
epubSize = (os.path.getsize(self.kindlegenErrorCode[2]))/1024/1024
|
||||||
@@ -571,10 +576,10 @@ class KCCGUI(KCC_ui.Ui_KCC):
|
|||||||
else:
|
else:
|
||||||
dnames = ""
|
dnames = ""
|
||||||
for dname in dnames:
|
for dname in dnames:
|
||||||
if unicode(dname) != "":
|
if str(dname) != "":
|
||||||
if sys.platform == 'win32':
|
if sys.platform == 'win32':
|
||||||
dname = dname.replace('/', '\\')
|
dname = dname.replace('/', '\\')
|
||||||
self.lastPath = os.path.abspath(os.path.join(unicode(dname), os.pardir))
|
self.lastPath = os.path.abspath(os.path.join(str(dname), os.pardir))
|
||||||
GUI.JobList.addItem(dname)
|
GUI.JobList.addItem(dname)
|
||||||
MW.setFocus()
|
MW.setFocus()
|
||||||
|
|
||||||
@@ -597,8 +602,8 @@ class KCCGUI(KCC_ui.Ui_KCC):
|
|||||||
fnames = QtGui.QFileDialog.getOpenFileNames(MW, 'Select file', self.lastPath,
|
fnames = QtGui.QFileDialog.getOpenFileNames(MW, 'Select file', self.lastPath,
|
||||||
'*.cbz *.zip *.pdf')
|
'*.cbz *.zip *.pdf')
|
||||||
for fname in fnames:
|
for fname in fnames:
|
||||||
if unicode(fname) != "":
|
if str(fname) != "":
|
||||||
self.lastPath = os.path.abspath(os.path.join(unicode(fname), os.pardir))
|
self.lastPath = os.path.abspath(os.path.join(str(fname), os.pardir))
|
||||||
GUI.JobList.addItem(fname)
|
GUI.JobList.addItem(fname)
|
||||||
|
|
||||||
def clearJobs(self):
|
def clearJobs(self):
|
||||||
@@ -884,19 +889,19 @@ class KCCGUI(KCC_ui.Ui_KCC):
|
|||||||
self.settings.setValue('currentFormat', GUI.FormatBox.currentIndex())
|
self.settings.setValue('currentFormat', GUI.FormatBox.currentIndex())
|
||||||
self.settings.setValue('currentMode', self.currentMode)
|
self.settings.setValue('currentMode', self.currentMode)
|
||||||
self.settings.setValue('firstStart', False)
|
self.settings.setValue('firstStart', False)
|
||||||
self.settings.setValue('options', QtCore.QVariant({'MangaBox': GUI.MangaBox.checkState(),
|
self.settings.setValue('options', {'MangaBox': GUI.MangaBox.checkState(),
|
||||||
'RotateBox': GUI.RotateBox.checkState(),
|
'RotateBox': GUI.RotateBox.checkState(),
|
||||||
'QualityBox': GUI.QualityBox.checkState(),
|
'QualityBox': GUI.QualityBox.checkState(),
|
||||||
'ProcessingBox': GUI.ProcessingBox.checkState(),
|
'ProcessingBox': GUI.ProcessingBox.checkState(),
|
||||||
'UpscaleBox': GUI.UpscaleBox.checkState(),
|
'UpscaleBox': GUI.UpscaleBox.checkState(),
|
||||||
'NoRotateBox': GUI.NoRotateBox.checkState(),
|
'NoRotateBox': GUI.NoRotateBox.checkState(),
|
||||||
'BorderBox': GUI.BorderBox.checkState(),
|
'BorderBox': GUI.BorderBox.checkState(),
|
||||||
'WebtoonBox': GUI.WebtoonBox.checkState(),
|
'WebtoonBox': GUI.WebtoonBox.checkState(),
|
||||||
'NoDitheringBox': GUI.NoDitheringBox.checkState(),
|
'NoDitheringBox': GUI.NoDitheringBox.checkState(),
|
||||||
'ColorBox': GUI.ColorBox.checkState(),
|
'ColorBox': GUI.ColorBox.checkState(),
|
||||||
'customWidth': GUI.customWidth.text(),
|
'customWidth': GUI.customWidth.text(),
|
||||||
'customHeight': GUI.customHeight.text(),
|
'customHeight': GUI.customHeight.text(),
|
||||||
'GammaSlider': float(self.GammaValue)*100}))
|
'GammaSlider': float(self.GammaValue)*100})
|
||||||
self.settings.sync()
|
self.settings.sync()
|
||||||
|
|
||||||
def handleMessage(self, message):
|
def handleMessage(self, message):
|
||||||
@@ -947,8 +952,7 @@ class KCCGUI(KCC_ui.Ui_KCC):
|
|||||||
self.currentMode = self.settings.value('currentMode', 1, type=int)
|
self.currentMode = self.settings.value('currentMode', 1, type=int)
|
||||||
self.currentFormat = self.settings.value('currentFormat', 0, type=int)
|
self.currentFormat = self.settings.value('currentFormat', 0, type=int)
|
||||||
self.firstStart = self.settings.value('firstStart', True, type=bool)
|
self.firstStart = self.settings.value('firstStart', True, type=bool)
|
||||||
self.options = self.settings.value('options', QtCore.QVariant({'GammaSlider': 0}))
|
self.options = self.settings.value('options', {'GammaSlider': 0})
|
||||||
self.options = self.options.toPyObject()
|
|
||||||
self.worker = WorkerThread()
|
self.worker = WorkerThread()
|
||||||
self.versionCheck = VersionThread()
|
self.versionCheck = VersionThread()
|
||||||
self.contentServer = WebServerThread()
|
self.contentServer = WebServerThread()
|
||||||
@@ -996,7 +1000,8 @@ class KCCGUI(KCC_ui.Ui_KCC):
|
|||||||
formats = ['MOBI', 'EPUB', 'CBZ']
|
formats = ['MOBI', 'EPUB', 'CBZ']
|
||||||
versionCheck = Popen('kindlegen -locale en', stdout=PIPE, stderr=STDOUT, shell=True)
|
versionCheck = Popen('kindlegen -locale en', stdout=PIPE, stderr=STDOUT, shell=True)
|
||||||
for line in versionCheck.stdout:
|
for line in versionCheck.stdout:
|
||||||
if "Amazon kindlegen" in line:
|
line = line.decode("utf-8")
|
||||||
|
if 'Amazon kindlegen' in line:
|
||||||
versionCheck = line.split('V')[1].split(' ')[0]
|
versionCheck = line.split('V')[1].split(' ')[0]
|
||||||
if tuple(map(int, (versionCheck.split(".")))) < tuple(map(int, ('2.9'.split(".")))):
|
if tuple(map(int, (versionCheck.split(".")))) < tuple(map(int, ('2.9'.split(".")))):
|
||||||
self.addMessage('Your <a href="http://www.amazon.com/gp/feature.html?ie=UTF8&docId='
|
self.addMessage('Your <a href="http://www.amazon.com/gp/feature.html?ie=UTF8&docId='
|
||||||
|
|||||||
@@ -2,14 +2,14 @@
|
|||||||
|
|
||||||
# Resource object code
|
# Resource object code
|
||||||
#
|
#
|
||||||
# Created: N 6. paź 13:26:15 2013
|
# Created: mer nov 13 21:20:16 2013
|
||||||
# by: The Resource Compiler for PyQt (Qt v4.8.5)
|
# by: The Resource Compiler for PyQt (Qt v4.8.6)
|
||||||
#
|
#
|
||||||
# WARNING! All changes made in this file will be lost!
|
# WARNING! All changes made in this file will be lost!
|
||||||
|
|
||||||
from PyQt4 import QtCore
|
from PyQt4 import QtCore
|
||||||
|
|
||||||
qt_resource_data = "\
|
qt_resource_data = b"\
|
||||||
\x00\x00\x09\x59\
|
\x00\x00\x09\x59\
|
||||||
\x89\
|
\x89\
|
||||||
\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
|
\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
|
||||||
@@ -8360,7 +8360,7 @@ qt_resource_data = "\
|
|||||||
\xfc\xce\x76\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\
|
\xfc\xce\x76\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\
|
||||||
"
|
"
|
||||||
|
|
||||||
qt_resource_name = "\
|
qt_resource_name = b"\
|
||||||
\x00\x07\
|
\x00\x07\
|
||||||
\x0a\xcc\xf9\x43\
|
\x0a\xcc\xf9\x43\
|
||||||
\x00\x44\
|
\x00\x44\
|
||||||
@@ -8444,7 +8444,7 @@ qt_resource_name = "\
|
|||||||
\x00\x74\x00\x68\x00\x65\x00\x72\x00\x2e\x00\x70\x00\x6e\x00\x67\
|
\x00\x74\x00\x68\x00\x65\x00\x72\x00\x2e\x00\x70\x00\x6e\x00\x67\
|
||||||
"
|
"
|
||||||
|
|
||||||
qt_resource_struct = "\
|
qt_resource_struct = b"\
|
||||||
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x05\x00\x00\x00\x01\
|
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x05\x00\x00\x00\x01\
|
||||||
\x00\x00\x00\x28\x00\x02\x00\x00\x00\x01\x00\x00\x00\x17\
|
\x00\x00\x00\x28\x00\x02\x00\x00\x00\x01\x00\x00\x00\x17\
|
||||||
\x00\x00\x00\x36\x00\x02\x00\x00\x00\x01\x00\x00\x00\x11\
|
\x00\x00\x00\x36\x00\x02\x00\x00\x00\x01\x00\x00\x00\x11\
|
||||||
|
|||||||
@@ -321,4 +321,4 @@ class Ui_KCC(object):
|
|||||||
self.ActionBasic.setText(_translate("KCC", "Basic", None))
|
self.ActionBasic.setText(_translate("KCC", "Basic", None))
|
||||||
self.ActionAdvanced.setText(_translate("KCC", "Advanced", None))
|
self.ActionAdvanced.setText(_translate("KCC", "Advanced", None))
|
||||||
|
|
||||||
import KCC_rc
|
from . import KCC_rc
|
||||||
|
|||||||
@@ -390,4 +390,4 @@ class Ui_KCC(object):
|
|||||||
self.ActionBasic.setText(_translate("KCC", "Basic", None))
|
self.ActionBasic.setText(_translate("KCC", "Basic", None))
|
||||||
self.ActionAdvanced.setText(_translate("KCC", "Advanced", None))
|
self.ActionAdvanced.setText(_translate("KCC", "Advanced", None))
|
||||||
|
|
||||||
import KCC_rc
|
from . import KCC_rc
|
||||||
|
|||||||
@@ -408,4 +408,4 @@ class Ui_KCC(object):
|
|||||||
self.ActionBasic.setText(_translate("KCC", "Basic", None))
|
self.ActionBasic.setText(_translate("KCC", "Basic", None))
|
||||||
self.ActionAdvanced.setText(_translate("KCC", "Advanced", None))
|
self.ActionAdvanced.setText(_translate("KCC", "Advanced", None))
|
||||||
|
|
||||||
import KCC_rc
|
from . import KCC_rc
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
__version__ = '3.6'
|
__version__ = '4.0'
|
||||||
__license__ = 'ISC'
|
__license__ = 'ISC'
|
||||||
__copyright__ = '2012-2013, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@vulturis.eu>'
|
__copyright__ = '2012-2013, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@vulturis.eu>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
2
kcc/__main__.py
Normal file
2
kcc/__main__.py
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
from kcc.comic2ebook import main
|
||||||
|
main()
|
||||||
@@ -21,7 +21,7 @@ __docformat__ = 'restructuredtext en'
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import zipfile
|
import zipfile
|
||||||
import rarfile
|
from . import rarfile
|
||||||
import locale
|
import locale
|
||||||
from subprocess import STDOUT, PIPE
|
from subprocess import STDOUT, PIPE
|
||||||
from psutil import Popen
|
from psutil import Popen
|
||||||
@@ -52,7 +52,7 @@ class CBxArchive:
|
|||||||
elif f.endswith('/'):
|
elif f.endswith('/'):
|
||||||
try:
|
try:
|
||||||
os.makedirs(os.path.join(targetdir, f))
|
os.makedirs(os.path.join(targetdir, f))
|
||||||
except StandardError:
|
except Exception:
|
||||||
pass # the dir exists so we are going to extract the images only.
|
pass # the dir exists so we are going to extract the images only.
|
||||||
else:
|
else:
|
||||||
filelist.append(f)
|
filelist.append(f)
|
||||||
@@ -67,7 +67,7 @@ class CBxArchive:
|
|||||||
elif f.endswith('/'):
|
elif f.endswith('/'):
|
||||||
try:
|
try:
|
||||||
os.makedirs(os.path.join(targetdir, f))
|
os.makedirs(os.path.join(targetdir, f))
|
||||||
except StandardError:
|
except Exception:
|
||||||
pass # the dir exists so we are going to extract the images only.
|
pass # the dir exists so we are going to extract the images only.
|
||||||
else:
|
else:
|
||||||
filelist.append(f.encode(locale.getpreferredencoding()))
|
filelist.append(f.encode(locale.getpreferredencoding()))
|
||||||
@@ -85,7 +85,7 @@ class CBxArchive:
|
|||||||
raise OSError
|
raise OSError
|
||||||
|
|
||||||
def extract(self, targetdir):
|
def extract(self, targetdir):
|
||||||
print "\n" + targetdir + "\n"
|
print("\n" + targetdir + "\n")
|
||||||
if self.compressor == 'rar':
|
if self.compressor == 'rar':
|
||||||
self.extractCBR(targetdir)
|
self.extractCBR(targetdir)
|
||||||
elif self.compressor == 'zip':
|
elif self.compressor == 'zip':
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python2
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Copyright (c) 2012-2013 Ciro Mattia Gonano <ciromattia@gmail.com>
|
# Copyright (c) 2012-2013 Ciro Mattia Gonano <ciromattia@gmail.com>
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
# 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.
|
||||||
#
|
#
|
||||||
__version__ = '3.6'
|
__version__ = '4.0'
|
||||||
__license__ = 'ISC'
|
__license__ = 'ISC'
|
||||||
__copyright__ = '2012-2013, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@vulturis.eu>'
|
__copyright__ = '2012-2013, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@vulturis.eu>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
@@ -35,14 +35,15 @@ from optparse import OptionParser, OptionGroup
|
|||||||
from multiprocessing import Pool, freeze_support
|
from multiprocessing import Pool, freeze_support
|
||||||
from xml.dom.minidom import parse
|
from xml.dom.minidom import parse
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
|
from slugify import slugify
|
||||||
try:
|
try:
|
||||||
from PyQt4 import QtCore
|
from PyQt4 import QtCore
|
||||||
except ImportError:
|
except ImportError:
|
||||||
QtCore = None
|
QtCore = None
|
||||||
import comic2panel
|
from . import comic2panel
|
||||||
import image
|
from . import image
|
||||||
import cbxarchive
|
from . import cbxarchive
|
||||||
import pdfjpgextract
|
from . import pdfjpgextract
|
||||||
|
|
||||||
|
|
||||||
def buildHTML(path, imgfile):
|
def buildHTML(path, imgfile):
|
||||||
@@ -172,7 +173,6 @@ def buildHTML(path, imgfile):
|
|||||||
|
|
||||||
def buildNCX(dstdir, title, chapters):
|
def buildNCX(dstdir, title, chapters):
|
||||||
options.uuid = str(uuid4())
|
options.uuid = str(uuid4())
|
||||||
options.uuid = options.uuid.encode('utf-8')
|
|
||||||
ncxfile = os.path.join(dstdir, 'OEBPS', 'toc.ncx')
|
ncxfile = os.path.join(dstdir, 'OEBPS', 'toc.ncx')
|
||||||
f = open(ncxfile, "w")
|
f = open(ncxfile, "w")
|
||||||
f.writelines(["<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n",
|
f.writelines(["<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n",
|
||||||
@@ -186,7 +186,7 @@ def buildNCX(dstdir, title, chapters):
|
|||||||
"<meta name=\"dtb:maxPageNumber\" content=\"0\"/>\n",
|
"<meta name=\"dtb:maxPageNumber\" content=\"0\"/>\n",
|
||||||
"<meta name=\"generated\" content=\"true\"/>\n",
|
"<meta name=\"generated\" content=\"true\"/>\n",
|
||||||
"</head>\n",
|
"</head>\n",
|
||||||
"<docTitle><text>", title.encode('utf-8'), "</text></docTitle>\n",
|
"<docTitle><text>", title, "</text></docTitle>\n",
|
||||||
"<navMap>"
|
"<navMap>"
|
||||||
])
|
])
|
||||||
for chapter in chapters:
|
for chapter in chapters:
|
||||||
@@ -195,7 +195,7 @@ def buildNCX(dstdir, title, chapters):
|
|||||||
title = os.path.basename(folder)
|
title = os.path.basename(folder)
|
||||||
filename = getImageFileName(os.path.join(folder, chapter[1]))
|
filename = getImageFileName(os.path.join(folder, chapter[1]))
|
||||||
f.write("<navPoint id=\"" + folder.replace('/', '_').replace('\\', '_') + "\"><navLabel><text>"
|
f.write("<navPoint id=\"" + folder.replace('/', '_').replace('\\', '_') + "\"><navLabel><text>"
|
||||||
+ title.encode('utf-8') + "</text></navLabel><content src=\"" + filename[0].replace("\\", "/")
|
+ title + "</text></navLabel><content src=\"" + filename[0].replace("\\", "/")
|
||||||
+ ".html\"/></navPoint>\n")
|
+ ".html\"/></navPoint>\n")
|
||||||
f.write("</navMap>\n</ncx>")
|
f.write("</navMap>\n</ncx>")
|
||||||
f.close()
|
f.close()
|
||||||
@@ -216,11 +216,11 @@ def buildOPF(dstdir, title, filelist, cover=None):
|
|||||||
"xmlns=\"http://www.idpf.org/2007/opf\">\n",
|
"xmlns=\"http://www.idpf.org/2007/opf\">\n",
|
||||||
"<metadata xmlns:opf=\"http://www.idpf.org/2007/opf\" ",
|
"<metadata xmlns:opf=\"http://www.idpf.org/2007/opf\" ",
|
||||||
"xmlns:dc=\"http://purl.org/dc/elements/1.1/\">\n",
|
"xmlns:dc=\"http://purl.org/dc/elements/1.1/\">\n",
|
||||||
"<dc:title>", title.encode('utf-8'), "</dc:title>\n",
|
"<dc:title>", title, "</dc:title>\n",
|
||||||
"<dc:language>en-US</dc:language>\n",
|
"<dc:language>en-US</dc:language>\n",
|
||||||
"<dc:identifier id=\"BookID\" opf:scheme=\"UUID\">", options.uuid, "</dc:identifier>\n"])
|
"<dc:identifier id=\"BookID\" opf:scheme=\"UUID\">", options.uuid, "</dc:identifier>\n"])
|
||||||
for author in options.authors:
|
for author in options.authors:
|
||||||
f.writelines(["<dc:Creator>", author.encode('utf-8'), "</dc:Creator>\n"])
|
f.writelines(["<dc:Creator>", author, "</dc:Creator>\n"])
|
||||||
f.writelines(["<meta name=\"generator\" content=\"KindleComicConverter-" + __version__ + "\"/>\n",
|
f.writelines(["<meta name=\"generator\" content=\"KindleComicConverter-" + __version__ + "\"/>\n",
|
||||||
"<meta name=\"RegionMagnification\" content=\"true\"/>\n",
|
"<meta name=\"RegionMagnification\" content=\"true\"/>\n",
|
||||||
"<meta name=\"region-mag\" content=\"true\"/>\n",
|
"<meta name=\"region-mag\" content=\"true\"/>\n",
|
||||||
@@ -356,9 +356,9 @@ def fileImgProcess(work):
|
|||||||
dirpath = work[1]
|
dirpath = work[1]
|
||||||
opt = work[2]
|
opt = work[2]
|
||||||
if opt.verbose:
|
if opt.verbose:
|
||||||
print "Optimizing " + afile + " for " + opt.profile
|
print("Optimizing " + afile + " for " + opt.profile)
|
||||||
else:
|
else:
|
||||||
print ".",
|
print(".", end=' ')
|
||||||
img = image.ComicPage(os.path.join(dirpath, afile), opt.profileData)
|
img = image.ComicPage(os.path.join(dirpath, afile), opt.profileData)
|
||||||
if opt.quality == 2:
|
if opt.quality == 2:
|
||||||
wipe = False
|
wipe = False
|
||||||
@@ -370,7 +370,7 @@ def fileImgProcess(work):
|
|||||||
split = img.splitPage(dirpath, opt.righttoleft, opt.rotate)
|
split = img.splitPage(dirpath, opt.righttoleft, opt.rotate)
|
||||||
if split is not None:
|
if split is not None:
|
||||||
if opt.verbose:
|
if opt.verbose:
|
||||||
print "Splitted " + afile
|
print("Splitted " + afile)
|
||||||
img0 = image.ComicPage(split[0], opt.profileData)
|
img0 = image.ComicPage(split[0], opt.profileData)
|
||||||
applyImgOptimization(img0, opt)
|
applyImgOptimization(img0, opt)
|
||||||
img0.saveToDir(dirpath, opt.forcepng, opt.forcecolor, wipe)
|
img0.saveToDir(dirpath, opt.forcepng, opt.forcecolor, wipe)
|
||||||
@@ -394,7 +394,9 @@ def fileImgProcess(work):
|
|||||||
img2.rotated = True
|
img2.rotated = True
|
||||||
applyImgOptimization(img2, opt, 0)
|
applyImgOptimization(img2, opt, 0)
|
||||||
img2.saveToDir(dirpath, opt.forcepng, opt.forcecolor, True)
|
img2.saveToDir(dirpath, opt.forcepng, opt.forcecolor, True)
|
||||||
except StandardError:
|
except Exception:
|
||||||
|
import traceback
|
||||||
|
traceback.print_tb(sys.exc_info()[2])
|
||||||
return str(sys.exc_info()[1])
|
return str(sys.exc_info()[1])
|
||||||
|
|
||||||
|
|
||||||
@@ -565,7 +567,7 @@ def getWorkFolder(afile):
|
|||||||
path = cbx.extract(workdir)
|
path = cbx.extract(workdir)
|
||||||
except OSError:
|
except OSError:
|
||||||
rmtree(workdir, True)
|
rmtree(workdir, True)
|
||||||
print 'UnRAR/7za not found or file failed to extract!'
|
print('UnRAR/7za not found or file failed to extract!')
|
||||||
sys.exit(21)
|
sys.exit(21)
|
||||||
else:
|
else:
|
||||||
rmtree(workdir, True)
|
rmtree(workdir, True)
|
||||||
@@ -592,7 +594,7 @@ def checkComicInfo(path, originalPath):
|
|||||||
if os.path.exists(xmlPath):
|
if os.path.exists(xmlPath):
|
||||||
try:
|
try:
|
||||||
xml = parse(xmlPath)
|
xml = parse(xmlPath)
|
||||||
except StandardError:
|
except Exception:
|
||||||
os.remove(xmlPath)
|
os.remove(xmlPath)
|
||||||
return
|
return
|
||||||
options.authors = []
|
options.authors = []
|
||||||
@@ -628,18 +630,14 @@ def checkComicInfo(path, originalPath):
|
|||||||
os.remove(xmlPath)
|
os.remove(xmlPath)
|
||||||
|
|
||||||
|
|
||||||
def slugify(value):
|
#def slugify(value):
|
||||||
# Normalizes string, converts to lowercase, removes non-alpha characters and converts spaces to hyphens.
|
# # Normalizes string, converts to lowercase, removes non-alpha characters and converts spaces to hyphens.
|
||||||
if isinstance(value, str):
|
# value = unicodedata.normalize('NFKD', value).encode('ascii', 'ignore')
|
||||||
#noinspection PyArgumentList
|
# value = re.sub('[^\w\s\.-]', '', value).strip().lower()
|
||||||
value = unicodedata.normalize('NFKD', unicode(value, 'latin1')).encode('ascii', 'ignore')
|
# value = re.sub('[-\.\s]+', '-', value)
|
||||||
elif isinstance(value, unicode):
|
# value = re.sub(r'([0-9]+)', r'00000\1', value)
|
||||||
value = unicodedata.normalize('NFKD', value).encode('ascii', 'ignore')
|
# value = re.sub(r'0*([0-9]{6,})', r'\1', value)
|
||||||
value = re.sub('[^\w\s\.-]', '', value).strip().lower()
|
# return value
|
||||||
value = re.sub('[-\.\s]+', '-', value)
|
|
||||||
value = re.sub(r'([0-9]+)', r'00000\1', value)
|
|
||||||
value = re.sub(r'0*([0-9]{6,})', r'\1', value)
|
|
||||||
return value
|
|
||||||
|
|
||||||
|
|
||||||
def sanitizeTree(filetree):
|
def sanitizeTree(filetree):
|
||||||
@@ -775,7 +773,7 @@ def preSplitDirectory(path):
|
|||||||
mode = 0
|
mode = 0
|
||||||
else:
|
else:
|
||||||
if filesNumber > 0:
|
if filesNumber > 0:
|
||||||
print '\nWARNING: Automatic output splitting failed.'
|
print('\nWARNING: Automatic output splitting failed.')
|
||||||
if GUI:
|
if GUI:
|
||||||
GUI.emit(QtCore.SIGNAL("addMessage"), 'Automatic output splitting failed. <a href='
|
GUI.emit(QtCore.SIGNAL("addMessage"), 'Automatic output splitting failed. <a href='
|
||||||
'"https://github.com/ciromattia/kcc/wiki'
|
'"https://github.com/ciromattia/kcc/wiki'
|
||||||
@@ -790,7 +788,7 @@ def preSplitDirectory(path):
|
|||||||
if len(dirs) != 0:
|
if len(dirs) != 0:
|
||||||
detectedSubSubdirectories = True
|
detectedSubSubdirectories = True
|
||||||
elif len(dirs) == 0 and detectedSubSubdirectories:
|
elif len(dirs) == 0 and detectedSubSubdirectories:
|
||||||
print '\nWARNING: Automatic output splitting failed.'
|
print('\nWARNING: Automatic output splitting failed.')
|
||||||
if GUI:
|
if GUI:
|
||||||
GUI.emit(QtCore.SIGNAL("addMessage"), 'Automatic output splitting failed. <a href='
|
GUI.emit(QtCore.SIGNAL("addMessage"), 'Automatic output splitting failed. <a href='
|
||||||
'"https://github.com/ciromattia/kcc/wiki'
|
'"https://github.com/ciromattia/kcc/wiki'
|
||||||
@@ -807,7 +805,7 @@ def preSplitDirectory(path):
|
|||||||
# One level of subdirectories
|
# One level of subdirectories
|
||||||
mode = 1
|
mode = 1
|
||||||
if detectedFilesInSubdirectories and detectedSubSubdirectories:
|
if detectedFilesInSubdirectories and detectedSubSubdirectories:
|
||||||
print '\nWARNING: Automatic output splitting failed.'
|
print('\nWARNING: Automatic output splitting failed.')
|
||||||
if GUI:
|
if GUI:
|
||||||
GUI.emit(QtCore.SIGNAL("addMessage"), 'Automatic output splitting failed. <a href='
|
GUI.emit(QtCore.SIGNAL("addMessage"), 'Automatic output splitting failed. <a href='
|
||||||
'"https://github.com/ciromattia/kcc/wiki'
|
'"https://github.com/ciromattia/kcc/wiki'
|
||||||
@@ -827,12 +825,12 @@ def preSplitDirectory(path):
|
|||||||
|
|
||||||
|
|
||||||
def Copyright():
|
def Copyright():
|
||||||
print ('comic2ebook v%(__version__)s. '
|
print(('comic2ebook v%(__version__)s. '
|
||||||
'Written 2013 by Ciro Mattia Gonano and Pawel Jastrzebski.' % globals())
|
'Written 2013 by Ciro Mattia Gonano and Pawel Jastrzebski.' % globals()))
|
||||||
|
|
||||||
|
|
||||||
def Usage():
|
def Usage():
|
||||||
print "Generates EPUB/CBZ comic ebook from a bunch of images."
|
print("Generates EPUB/CBZ comic ebook from a bunch of images.")
|
||||||
parser.print_help()
|
parser.print_help()
|
||||||
|
|
||||||
|
|
||||||
@@ -916,7 +914,7 @@ def main(argv=None, qtGUI=None):
|
|||||||
else:
|
else:
|
||||||
comic2panel.main(['-y ' + str(image.ProfileData.Profiles[options.profile][1][1]), '-i', path], qtGUI)
|
comic2panel.main(['-y ' + str(image.ProfileData.Profiles[options.profile][1][1]), '-i', path], qtGUI)
|
||||||
if options.imgproc:
|
if options.imgproc:
|
||||||
print "\nProcessing images..."
|
print("\nProcessing images...")
|
||||||
if GUI:
|
if GUI:
|
||||||
GUI.emit(QtCore.SIGNAL("progressBarTick"), 'status', 'Processing images')
|
GUI.emit(QtCore.SIGNAL("progressBarTick"), 'status', 'Processing images')
|
||||||
dirImgProcess(path + "/OEBPS/Images/")
|
dirImgProcess(path + "/OEBPS/Images/")
|
||||||
@@ -943,14 +941,14 @@ def main(argv=None, qtGUI=None):
|
|||||||
options.title = options.baseTitle + ' [' + str(tomeNumber) + '/' + str(len(tomes)) + ']'
|
options.title = options.baseTitle + ' [' + str(tomeNumber) + '/' + str(len(tomes)) + ']'
|
||||||
if options.cbzoutput:
|
if options.cbzoutput:
|
||||||
# if CBZ output wanted, compress all images and return filepath
|
# if CBZ output wanted, compress all images and return filepath
|
||||||
print "\nCreating CBZ file..."
|
print("\nCreating CBZ file...")
|
||||||
if len(tomes) > 1:
|
if len(tomes) > 1:
|
||||||
filepath.append(getOutputFilename(args[0], options.output, '.cbz', ' ' + str(tomeNumber)))
|
filepath.append(getOutputFilename(args[0], options.output, '.cbz', ' ' + str(tomeNumber)))
|
||||||
else:
|
else:
|
||||||
filepath.append(getOutputFilename(args[0], options.output, '.cbz', ''))
|
filepath.append(getOutputFilename(args[0], options.output, '.cbz', ''))
|
||||||
make_archive(tome + '_comic', 'zip', tome + '/OEBPS/Images')
|
make_archive(tome + '_comic', 'zip', tome + '/OEBPS/Images')
|
||||||
else:
|
else:
|
||||||
print "\nCreating EPUB structure..."
|
print("\nCreating EPUB structure...")
|
||||||
genEpubStruct(tome)
|
genEpubStruct(tome)
|
||||||
# actually zip the ePub
|
# actually zip the ePub
|
||||||
if len(tomes) > 1:
|
if len(tomes) > 1:
|
||||||
@@ -1017,7 +1015,7 @@ def checkOptions():
|
|||||||
options.quality = 0
|
options.quality = 0
|
||||||
# Kindle for Android profile require target resolution.
|
# Kindle for Android profile require target resolution.
|
||||||
if options.profile == 'KFA' and (options.customwidth == 0 or options.customheight == 0):
|
if options.profile == 'KFA' and (options.customwidth == 0 or options.customheight == 0):
|
||||||
print "ERROR: Kindle for Android profile require --customwidth and --customheight options!"
|
print("ERROR: Kindle for Android profile require --customwidth and --customheight options!")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
# Override profile data
|
# Override profile data
|
||||||
if options.customwidth != 0 or options.customheight != 0:
|
if options.customwidth != 0 or options.customheight != 0:
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
# 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.
|
||||||
#
|
#
|
||||||
__version__ = '3.6'
|
__version__ = '4.0'
|
||||||
__license__ = 'ISC'
|
__license__ = 'ISC'
|
||||||
__copyright__ = '2012-2013, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@vulturis.eu>'
|
__copyright__ = '2012-2013, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@vulturis.eu>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
@@ -32,26 +32,26 @@ try:
|
|||||||
#noinspection PyUnresolvedReferences
|
#noinspection PyUnresolvedReferences
|
||||||
from PIL import Image, ImageStat
|
from PIL import Image, ImageStat
|
||||||
if tuple(map(int, ('2.2.1'.split(".")))) > tuple(map(int, (Image.PILLOW_VERSION.split(".")))):
|
if tuple(map(int, ('2.2.1'.split(".")))) > tuple(map(int, (Image.PILLOW_VERSION.split(".")))):
|
||||||
print "ERROR: Pillow 2.2.1 or newer is required!"
|
print("ERROR: Pillow 2.2.1 or newer is required!")
|
||||||
if sys.platform.startswith('linux'):
|
if sys.platform.startswith('linux'):
|
||||||
#noinspection PyUnresolvedReferences
|
#noinspection PyUnresolvedReferences
|
||||||
import Tkinter
|
import tkinter
|
||||||
#noinspection PyUnresolvedReferences
|
#noinspection PyUnresolvedReferences
|
||||||
import tkMessageBox
|
import tkinter.messagebox
|
||||||
importRoot = Tkinter.Tk()
|
importRoot = tkinter.Tk()
|
||||||
importRoot.withdraw()
|
importRoot.withdraw()
|
||||||
tkMessageBox.showerror("KCC - Error", "Pillow 2.2.1 or newer is required!")
|
tkinter.messagebox.showerror("KCC - Error", "Pillow 2.2.1 or newer is required!")
|
||||||
exit(1)
|
exit(1)
|
||||||
except ImportError:
|
except ImportError:
|
||||||
print "ERROR: Pillow is not installed!"
|
print("ERROR: Pillow is not installed!")
|
||||||
if sys.platform.startswith('linux'):
|
if sys.platform.startswith('linux'):
|
||||||
#noinspection PyUnresolvedReferences
|
#noinspection PyUnresolvedReferences
|
||||||
import Tkinter
|
import tkinter
|
||||||
#noinspection PyUnresolvedReferences
|
#noinspection PyUnresolvedReferences
|
||||||
import tkMessageBox
|
import tkinter.messagebox
|
||||||
importRoot = Tkinter.Tk()
|
importRoot = tkinter.Tk()
|
||||||
importRoot.withdraw()
|
importRoot.withdraw()
|
||||||
tkMessageBox.showerror("KCC - Error", "Pillow 2.2.1 or newer is required!")
|
tkinter.messagebox.showerror("KCC - Error", "Pillow 2.2.1 or newer is required!")
|
||||||
exit(1)
|
exit(1)
|
||||||
try:
|
try:
|
||||||
from PyQt4 import QtCore
|
from PyQt4 import QtCore
|
||||||
@@ -118,7 +118,7 @@ def splitImage(work):
|
|||||||
# Harcoded opttions
|
# Harcoded opttions
|
||||||
threshold = 1.0
|
threshold = 1.0
|
||||||
delta = 15
|
delta = 15
|
||||||
print ".",
|
print(".", end=' ')
|
||||||
fileExpanded = os.path.splitext(name)
|
fileExpanded = os.path.splitext(name)
|
||||||
filePath = os.path.join(path, name)
|
filePath = os.path.join(path, name)
|
||||||
# Detect corrupted files
|
# Detect corrupted files
|
||||||
@@ -210,13 +210,13 @@ def splitImage(work):
|
|||||||
str(pageNumber) + '.png'), 'PNG')
|
str(pageNumber) + '.png'), 'PNG')
|
||||||
pageNumber += 1
|
pageNumber += 1
|
||||||
os.remove(filePath)
|
os.remove(filePath)
|
||||||
except StandardError:
|
except Exception:
|
||||||
return str(sys.exc_info()[1])
|
return str(sys.exc_info()[1])
|
||||||
|
|
||||||
|
|
||||||
def Copyright():
|
def Copyright():
|
||||||
print ('comic2panel v%(__version__)s. '
|
print(('comic2panel v%(__version__)s. '
|
||||||
'Written 2013 by Ciro Mattia Gonano and Pawel Jastrzebski.' % globals())
|
'Written 2013 by Ciro Mattia Gonano and Pawel Jastrzebski.' % globals()))
|
||||||
|
|
||||||
|
|
||||||
def main(argv=None, qtGUI=None):
|
def main(argv=None, qtGUI=None):
|
||||||
@@ -245,7 +245,7 @@ def main(argv=None, qtGUI=None):
|
|||||||
if options.height > 0:
|
if options.height > 0:
|
||||||
options.sourceDir = args[0]
|
options.sourceDir = args[0]
|
||||||
options.targetDir = args[0] + "-Splitted"
|
options.targetDir = args[0] + "-Splitted"
|
||||||
print "\nSplitting images..."
|
print("\nSplitting images...")
|
||||||
if os.path.isdir(options.sourceDir):
|
if os.path.isdir(options.sourceDir):
|
||||||
rmtree(options.targetDir, True)
|
rmtree(options.targetDir, True)
|
||||||
copytree(options.sourceDir, options.targetDir)
|
copytree(options.sourceDir, options.targetDir)
|
||||||
|
|||||||
24
kcc/image.py
24
kcc/image.py
@@ -26,26 +26,26 @@ try:
|
|||||||
# noinspection PyUnresolvedReferences
|
# noinspection PyUnresolvedReferences
|
||||||
from PIL import Image, ImageOps, ImageStat, ImageChops
|
from PIL import Image, ImageOps, ImageStat, ImageChops
|
||||||
if tuple(map(int, ('2.2.1'.split(".")))) > tuple(map(int, (Image.PILLOW_VERSION.split(".")))):
|
if tuple(map(int, ('2.2.1'.split(".")))) > tuple(map(int, (Image.PILLOW_VERSION.split(".")))):
|
||||||
print "ERROR: Pillow 2.2.1 or newer is required!"
|
print("ERROR: Pillow 2.2.1 or newer is required!")
|
||||||
if platform.startswith('linux'):
|
if platform.startswith('linux'):
|
||||||
#noinspection PyUnresolvedReferences
|
#noinspection PyUnresolvedReferences
|
||||||
import Tkinter
|
import tkinter
|
||||||
#noinspection PyUnresolvedReferences
|
#noinspection PyUnresolvedReferences
|
||||||
import tkMessageBox
|
import tkinter.messagebox
|
||||||
importRoot = Tkinter.Tk()
|
importRoot = tkinter.Tk()
|
||||||
importRoot.withdraw()
|
importRoot.withdraw()
|
||||||
tkMessageBox.showerror("KCC - Error", "Pillow 2.2.1 or newer is required!")
|
tkinter.messagebox.showerror("KCC - Error", "Pillow 2.2.1 or newer is required!")
|
||||||
exit(1)
|
exit(1)
|
||||||
except ImportError:
|
except ImportError:
|
||||||
print "ERROR: Pillow is not installed!"
|
print("ERROR: Pillow is not installed!")
|
||||||
if platform.startswith('linux'):
|
if platform.startswith('linux'):
|
||||||
#noinspection PyUnresolvedReferences
|
#noinspection PyUnresolvedReferences
|
||||||
import Tkinter
|
import tkinter
|
||||||
#noinspection PyUnresolvedReferences
|
#noinspection PyUnresolvedReferences
|
||||||
import tkMessageBox
|
import tkinter.messagebox
|
||||||
importRoot = Tkinter.Tk()
|
importRoot = tkinter.Tk()
|
||||||
importRoot.withdraw()
|
importRoot.withdraw()
|
||||||
tkMessageBox.showerror("KCC - Error", "Pillow 2.2.1 or newer is required!")
|
tkinter.messagebox.showerror("KCC - Error", "Pillow 2.2.1 or newer is required!")
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
|
|
||||||
@@ -287,10 +287,10 @@ class ComicPage:
|
|||||||
ratioDev = float(self.size[0]) / float(self.size[1])
|
ratioDev = float(self.size[0]) / float(self.size[1])
|
||||||
if (float(self.image.size[0]) / float(self.image.size[1])) < ratioDev:
|
if (float(self.image.size[0]) / float(self.image.size[1])) < ratioDev:
|
||||||
diff = int(self.image.size[1] * ratioDev) - self.image.size[0]
|
diff = int(self.image.size[1] * ratioDev) - self.image.size[0]
|
||||||
self.image = ImageOps.expand(self.image, border=(diff / 2, 0), fill=fill)
|
self.image = ImageOps.expand(self.image, border=(int(diff / 2), 0), fill=fill)
|
||||||
elif (float(self.image.size[0]) / float(self.image.size[1])) > ratioDev:
|
elif (float(self.image.size[0]) / float(self.image.size[1])) > ratioDev:
|
||||||
diff = int(self.image.size[0] / ratioDev) - self.image.size[1]
|
diff = int(self.image.size[0] / ratioDev) - self.image.size[1]
|
||||||
self.image = ImageOps.expand(self.image, border=(0, diff / 2), fill=fill)
|
self.image = ImageOps.expand(self.image, border=(0, int(diff / 2)), fill=fill)
|
||||||
self.image = ImageOps.fit(self.image, size, method=method, centering=(0.5, 0.5))
|
self.image = ImageOps.fit(self.image, size, method=method, centering=(0.5, 0.5))
|
||||||
if generateBorder:
|
if generateBorder:
|
||||||
if fill == 'white':
|
if fill == 'white':
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
# Based on initial version of KindleUnpack. Copyright (C) 2009 Charles M. Hannum <root@ihack.net>
|
# Based on initial version of KindleUnpack. Copyright (C) 2009 Charles M. Hannum <root@ihack.net>
|
||||||
# Improvements Copyright (C) 2009-2012 P. Durrant, K. Hendricks, S. Siebert, fandrieu, DiapDealer, nickredding
|
# Improvements Copyright (C) 2009-2012 P. Durrant, K. Hendricks, S. Siebert, fandrieu, DiapDealer, nickredding
|
||||||
# Copyright (C) 2013 Pawel Jastrzebski <pawelj@vulturis.eu>
|
# Copyright (C) 2013 Pawel Jastrzebski <pawelj@vulturis.eu>
|
||||||
@@ -105,8 +108,8 @@ def nullsection(datain, secno): # make it zero-length without deleting it
|
|||||||
datalst.append('\0' * lpad)
|
datalst.append('\0' * lpad)
|
||||||
datalst.append(datain[zerosecstart: secstart])
|
datalst.append(datain[zerosecstart: secstart])
|
||||||
datalst.append(datain[secend:])
|
datalst.append(datain[secend:])
|
||||||
dataout = "".join(datalst)
|
dataout = "".join(str(datalst)[1:-1])
|
||||||
return dataout
|
return dataout.encode('utf-8')
|
||||||
|
|
||||||
|
|
||||||
def deletesectionrange(datain, firstsec, lastsec): # delete a range of sections
|
def deletesectionrange(datain, firstsec, lastsec): # delete a range of sections
|
||||||
@@ -135,8 +138,8 @@ def deletesectionrange(datain, firstsec, lastsec): # delete a range of sections
|
|||||||
datalst.append('\0' * lpad)
|
datalst.append('\0' * lpad)
|
||||||
datalst.append(datain[zerosecstart:firstsecstart])
|
datalst.append(datain[zerosecstart:firstsecstart])
|
||||||
datalst.append(datain[lastsecend:])
|
datalst.append(datain[lastsecend:])
|
||||||
dataout = "".join(datalst)
|
dataout = "".join(str(datalst)[1:-1])
|
||||||
return dataout
|
return dataout.encode('utf-8')
|
||||||
|
|
||||||
|
|
||||||
def insertsection(datain, secno, secdata): # insert a new section
|
def insertsection(datain, secno, secdata): # insert a new section
|
||||||
@@ -166,13 +169,14 @@ def insertsection(datain, secno, secdata): # insert a new section
|
|||||||
datalst.append(datain[zerosecstart:secstart])
|
datalst.append(datain[zerosecstart:secstart])
|
||||||
datalst.append(secdata)
|
datalst.append(secdata)
|
||||||
datalst.append(datain[secstart:])
|
datalst.append(datain[secstart:])
|
||||||
dataout = "".join(datalst)
|
dataout = "".join(str(datalst)[1:-1])
|
||||||
return dataout
|
return dataout.encode('utf-8')
|
||||||
|
|
||||||
|
|
||||||
def insertsectionrange(sectionsource, firstsec, lastsec, sectiontarget, targetsec): # insert a range of sections
|
def insertsectionrange(sectionsource, firstsec, lastsec, sectiontarget, targetsec): # insert a range of sections
|
||||||
dataout = sectiontarget
|
dataout = sectiontarget
|
||||||
for idx in range(lastsec, firstsec-1, -1):
|
for idx in range(lastsec, firstsec-1, -1):
|
||||||
|
print(dataout)
|
||||||
dataout = insertsection(dataout, targetsec, readsection(sectionsource, idx))
|
dataout = insertsection(dataout, targetsec, readsection(sectionsource, idx))
|
||||||
return dataout
|
return dataout
|
||||||
|
|
||||||
@@ -381,4 +385,10 @@ class mobi_split:
|
|||||||
raise
|
raise
|
||||||
|
|
||||||
def getResult(self):
|
def getResult(self):
|
||||||
return self.result_file
|
return self.result_file
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import sys
|
||||||
|
mobi_split(sys.argv[1], False)
|
||||||
|
sys.exit(0)
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ class PdfJpgExtract:
|
|||||||
|
|
||||||
istart += startfix
|
istart += startfix
|
||||||
iend += endfix
|
iend += endfix
|
||||||
print "JPG %d from %d to %d" % (njpg, istart, iend)
|
print("JPG %d from %d to %d" % (njpg, istart, iend))
|
||||||
jpg = pdf[istart:iend]
|
jpg = pdf[istart:iend]
|
||||||
jpgfile = file(self.path + "/jpg%d.jpg" % njpg, "wb")
|
jpgfile = file(self.path + "/jpg%d.jpg" % njpg, "wb")
|
||||||
jpgfile.write(jpg)
|
jpgfile.write(jpg)
|
||||||
|
|||||||
@@ -633,7 +633,7 @@ class RarFile(object):
|
|||||||
def printdir(self):
|
def printdir(self):
|
||||||
"""Print archive file list to stdout."""
|
"""Print archive file list to stdout."""
|
||||||
for f in self._info_list:
|
for f in self._info_list:
|
||||||
print(f.filename)
|
print((f.filename))
|
||||||
|
|
||||||
def extract(self, member, path=None, pwd=None):
|
def extract(self, member, path=None, pwd=None):
|
||||||
"""Extract single file into current directory.
|
"""Extract single file into current directory.
|
||||||
@@ -1138,7 +1138,7 @@ class RarFile(object):
|
|||||||
if self._crc_check:
|
if self._crc_check:
|
||||||
crc = crc32(cmt)
|
crc = crc32(cmt)
|
||||||
if crc < 0:
|
if crc < 0:
|
||||||
crc += (long(1) << 32)
|
crc += (int(1) << 32)
|
||||||
if crc != inf.CRC:
|
if crc != inf.CRC:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@@ -1342,7 +1342,7 @@ class RarExtFile(RawIOBase):
|
|||||||
raise BadRarFile("Failed the read enough data")
|
raise BadRarFile("Failed the read enough data")
|
||||||
crc = self.CRC
|
crc = self.CRC
|
||||||
if crc < 0:
|
if crc < 0:
|
||||||
crc += (long(1) << 32)
|
crc += (int(1) << 32)
|
||||||
if crc != self.inf.CRC:
|
if crc != self.inf.CRC:
|
||||||
raise BadRarFile("Corrupt file - CRC check failed: " + self.inf.filename)
|
raise BadRarFile("Corrupt file - CRC check failed: " + self.inf.filename)
|
||||||
|
|
||||||
|
|||||||
4
requirements.txt
Normal file
4
requirements.txt
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
Pillow==2.2.1
|
||||||
|
Unidecode==0.04.14
|
||||||
|
psutil==1.1.3
|
||||||
|
python-slugify==0.0.6
|
||||||
8
setup.py
8
setup.py
@@ -11,7 +11,7 @@ Usage (Windows):
|
|||||||
from sys import platform
|
from sys import platform
|
||||||
|
|
||||||
NAME = "KindleComicConverter"
|
NAME = "KindleComicConverter"
|
||||||
VERSION = "3.6"
|
VERSION = "4.0"
|
||||||
MAIN = "kcc.py"
|
MAIN = "kcc.py"
|
||||||
|
|
||||||
if platform == "darwin":
|
if platform == "darwin":
|
||||||
@@ -72,7 +72,7 @@ elif platform == "win32":
|
|||||||
appendScriptToLibrary=False,
|
appendScriptToLibrary=False,
|
||||||
compress=True)])
|
compress=True)])
|
||||||
else:
|
else:
|
||||||
print 'Please use setup.sh to build Linux package.'
|
print('Please use setup.sh to build Linux package.')
|
||||||
exit()
|
exit()
|
||||||
|
|
||||||
#noinspection PyUnboundLocalVariable
|
#noinspection PyUnboundLocalVariable
|
||||||
@@ -91,5 +91,5 @@ setup(
|
|||||||
|
|
||||||
if platform == "darwin":
|
if platform == "darwin":
|
||||||
from os import chmod
|
from os import chmod
|
||||||
chmod('dist/' + NAME + '.app/Contents/Resources/unrar', 0777)
|
chmod('dist/' + NAME + '.app/Contents/Resources/unrar', 0o777)
|
||||||
chmod('dist/' + NAME + '.app/Contents/Resources/7za', 0777)
|
chmod('dist/' + NAME + '.app/Contents/Resources/7za', 0o777)
|
||||||
Reference in New Issue
Block a user