1
0
mirror of https://github.com/ciromattia/kcc synced 2025-12-13 01:36:27 +00:00

Version 4.0 - first draft for Python3 conversion

This commit is contained in:
Ciro Mattia Gonano
2013-11-14 15:49:46 +01:00
parent ddd223c2ec
commit d33c53b691
19 changed files with 210 additions and 191 deletions

View File

@@ -1,5 +1,5 @@
#define MyAppName "Kindle Comic Converter"
#define MyAppVersion "3.6"
#define MyAppVersion "4.0"
#define MyAppPublisher "Ciro Mattia Gonano, Paweł Jastrzębski"
#define MyAppURL "http://kcc.vulturis.eu/"
#define MyAppExeName "KCC.exe"

12
kcc.py
View File

@@ -18,7 +18,7 @@
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
__version__ = '3.6'
__version__ = '4.0'
__license__ = 'ISC'
__copyright__ = '2012-2013, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@vulturis.eu>'
__docformat__ = 'restructuredtext en'
@@ -29,13 +29,13 @@ try:
#noinspection PyUnresolvedReferences
from PyQt4 import QtCore, QtGui, QtNetwork
except ImportError:
print "ERROR: PyQT4 is not installed!"
print("ERROR: PyQT4 is not installed!")
if sys.platform.startswith('linux'):
import Tkinter
import tkMessageBox
importRoot = Tkinter.Tk()
import tkinter
import tkinter.messagebox
importRoot = tkinter.Tk()
importRoot.withdraw()
tkMessageBox.showerror("KCC - Error", "PyQT4 is not installed!")
tkinter.messagebox.showerror("KCC - Error", "PyQT4 is not installed!")
exit(1)
from kcc import KCC_gui
from multiprocessing import freeze_support

View File

@@ -17,7 +17,7 @@
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
__version__ = '3.6'
__version__ = '4.0'
__license__ = 'ISC'
__copyright__ = '2012-2013, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@vulturis.eu>'
__docformat__ = 'restructuredtext en'
@@ -25,39 +25,38 @@ __docformat__ = 'restructuredtext en'
import os
import sys
import traceback
import urllib2
import urllib.request, urllib.error, urllib.parse
import socket
import comic2ebook
import kindlesplit
from string import split
from . import comic2ebook
from . import kindlesplit
from time import sleep
from shutil import move
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
from SocketServer import ThreadingMixIn
from image import ProfileData
from http.server import BaseHTTPRequestHandler, HTTPServer
from socketserver import ThreadingMixIn
from .image import ProfileData
from subprocess import STDOUT, PIPE
from PyQt4 import QtGui, QtCore
from xml.dom.minidom import parse
from HTMLParser import HTMLParser
from KCC_rc_web import WebContent
from html.parser import HTMLParser
from .KCC_rc_web import WebContent
try:
#noinspection PyUnresolvedReferences
from psutil import TOTAL_PHYMEM, Popen
except ImportError:
print "ERROR: Psutil is not installed!"
print("ERROR: Psutil is not installed!")
if sys.platform.startswith('linux'):
import Tkinter
import tkMessageBox
importRoot = Tkinter.Tk()
import tkinter
import tkinter.messagebox
importRoot = tkinter.Tk()
importRoot.withdraw()
tkMessageBox.showerror("KCC - Error", "Psutil is not installed!")
tkinter.messagebox.showerror("KCC - Error", "Psutil is not installed!")
exit(1)
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'):
import KCC_ui_linux as KCC_ui
from . import KCC_ui_linux as KCC_ui
else:
import KCC_ui
from . import KCC_ui
class Icons:
@@ -130,8 +129,8 @@ class WebServerHandler(BaseHTTPRequestHandler):
'<p style="font-size:50px">- <img style="vertical-align: middle" '
'alt="KCC Logo" src="' + GUI.webContent.logo + '" /> -</p>\n')
if len(GUI.completedWork) > 0 and not GUI.conversionAlive:
for key in sorted(GUI.completedWork.iterkeys()):
self.wfile.write('<p><a href="' + key + '">' + split(key, '.')[0] + '</a></p>\n')
for key in sorted(GUI.completedWork.keys()):
self.wfile.write('<p><a href="' + key + '">' + key.split('.')[0] + '</a></p>\n')
else:
self.wfile.write('<p style="font-weight: bold">No downloads are available.<br/>'
'Convert some files and refresh this page.</p>\n')
@@ -139,7 +138,7 @@ class WebServerHandler(BaseHTTPRequestHandler):
'</body>\n'
'</html>\n')
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')
self.send_response(200)
self.send_header('Content-type', mimetype)
@@ -173,7 +172,7 @@ class WebServerThread(QtCore.QThread):
try:
# 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]
except StandardError:
except Exception:
# Sadly it can fail on some Linux configurations
lIP = None
try:
@@ -186,7 +185,7 @@ class WebServerThread(QtCore.QThread):
self.emit(QtCore.SIGNAL("addMessage"), '<b>Content server</b> started on port 4242.', 'info')
while self.running:
self.server.handle_request()
except StandardError:
except Exception:
self.emit(QtCore.SIGNAL("addMessage"), '<b>Content server</b> failed to start!', 'error')
def stop(self):
@@ -202,9 +201,9 @@ class VersionThread(QtCore.QThread):
def run(self):
try:
XML = urllib2.urlopen('http://kcc.vulturis.eu/Version.php')
XML = urllib.request.urlopen('http://kcc.vulturis.eu/Version.php')
XML = parse(XML)
except StandardError:
except Exception:
return
latestVersion = XML.childNodes[0].getElementsByTagName('latest')[0].childNodes[0].toxml()
if tuple(map(int, (latestVersion.split(".")))) > tuple(map(int, (__version__.split(".")))):
@@ -253,9 +252,10 @@ class KindleGenThread(QtCore.QRunnable):
kindlegenError = ''
try:
if os.path.getsize(self.work) < 367001600:
output = Popen('kindlegen -locale en "' + self.work.encode(sys.getfilesystemencoding()) + '"',
stdout=PIPE, stderr=STDOUT, shell=True)
output = Popen('kindlegen -locale en "' + self.work.encode(sys.getfilesystemencoding()).decode('utf-8')
+ '"', stdout=PIPE, stderr=STDOUT, shell=True)
for line in output.stdout:
line = line.decode('utf-8')
# ERROR: Generic error
if "Error(" in line:
kindlegenErrorCode = 1
@@ -269,9 +269,10 @@ class KindleGenThread(QtCore.QRunnable):
# ERROR: EPUB too big
kindlegenErrorCode = 23026
self.signals.result.emit([kindlegenErrorCode, kindlegenError, self.work])
except StandardError:
# ERROR: Unknown generic error
except Exception as err:
# ERROR: KCC unknown generic error
kindlegenErrorCode = 1
kindlegenError = format(err)
self.signals.result.emit([kindlegenErrorCode, kindlegenError, self.work])
@@ -297,8 +298,9 @@ class KindleUnpackThread(QtCore.QRunnable):
mobisplit = kindlesplit.mobi_split(mobiPath + '_toclean', newKindle)
open(mobiPath, 'wb').write(mobisplit.getResult())
self.signals.result.emit([True])
except StandardError:
self.signals.result.emit([False])
except Exception as err:
traceback.print_exc()
self.signals.result.emit([False, format(err)])
class WorkerThread(QtCore.QThread):
@@ -385,7 +387,7 @@ class WorkerThread(QtCore.QThread):
for i in range(GUI.JobList.count()):
# Make sure that we don't consider any system message as job to do
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()
for job in currentJobs:
sleep(0.5)
@@ -466,42 +468,45 @@ class WorkerThread(QtCore.QThread):
if self.kindlegenErrorCode[0] == 0:
GUI.progress.content = ''
self.emit(QtCore.SIGNAL("addMessage"), 'Creating MOBI files... <b>Done!</b>', 'info', True)
self.emit(QtCore.SIGNAL("addMessage"), 'Cleaning MOBI files', 'info')
GUI.progress.content = 'Cleaning MOBI files'
self.workerOutput = []
# Multithreading KindleUnpack in current form is a waste of resources.
# Unless we higly optimise KindleUnpack or drop 32bit support this will not change.
self.pool.setMaxThreadCount(1)
for item in outputPath:
worker = KindleUnpackThread([item, profile])
worker.signals.result.connect(self.addResult)
self.pool.start(worker)
self.pool.waitForDone()
sleep(0.5)
for success in self.workerOutput:
if not success:
self.errors = True
break
if not self.errors:
for item in outputPath:
GUI.progress.content = ''
mobiPath = item.replace('.epub', '.mobi')
os.remove(mobiPath + '_toclean')
GUI.completedWork[os.path.basename(mobiPath).encode('utf-8')] = \
mobiPath.encode('utf-8')
self.emit(QtCore.SIGNAL("addMessage"), 'Cleaning MOBI files... <b>Done!</b>', 'info',
True)
else:
GUI.progress.content = ''
for item in outputPath:
mobiPath = item.replace('.epub', '.mobi')
if os.path.exists(mobiPath):
os.remove(mobiPath)
if os.path.exists(mobiPath + '_toclean'):
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')
self.emit(QtCore.SIGNAL("addMessage"), 'Cleaning MOBI files is currently disabled in this branch', 'info')
GUI.progress.content = 'Cleaning MOBI files is currently disabled in this branch'
#self.emit(QtCore.SIGNAL("addMessage"), 'Cleaning MOBI files', 'info')
#GUI.progress.content = 'Cleaning MOBI files'
#self.workerOutput = []
## Multithreading KindleUnpack in current form is a waste of resources.
## Unless we higly optimise KindleUnpack or drop 32bit support this will not change.
#self.pool.setMaxThreadCount(1)
#for item in outputPath:
# worker = KindleUnpackThread([item, profile])
# worker.signals.result.connect(self.addResult)
# self.pool.start(worker)
#self.pool.waitForDone()
#sleep(0.5)
#for success in self.workerOutput:
# if not success[0]:
# self.errors = True
# print(success[1])
# break
#if not self.errors:
# for item in outputPath:
# GUI.progress.content = ''
# mobiPath = item.replace('.epub', '.mobi')
# os.remove(mobiPath + '_toclean')
# GUI.completedWork[os.path.basename(mobiPath).encode('utf-8')] = \
# mobiPath.encode('utf-8')
# self.emit(QtCore.SIGNAL("addMessage"), 'Cleaning MOBI files... <b>Done!</b>', 'info',
# True)
#else:
# GUI.progress.content = ''
# for item in outputPath:
# mobiPath = item.replace('.epub', '.mobi')
# if os.path.exists(mobiPath):
# os.remove(mobiPath)
# if os.path.exists(mobiPath + '_toclean'):
# 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:
GUI.progress.content = ''
epubSize = (os.path.getsize(self.kindlegenErrorCode[2]))/1024/1024
@@ -571,10 +576,10 @@ class KCCGUI(KCC_ui.Ui_KCC):
else:
dnames = ""
for dname in dnames:
if unicode(dname) != "":
if str(dname) != "":
if sys.platform == 'win32':
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)
MW.setFocus()
@@ -597,8 +602,8 @@ class KCCGUI(KCC_ui.Ui_KCC):
fnames = QtGui.QFileDialog.getOpenFileNames(MW, 'Select file', self.lastPath,
'*.cbz *.zip *.pdf')
for fname in fnames:
if unicode(fname) != "":
self.lastPath = os.path.abspath(os.path.join(unicode(fname), os.pardir))
if str(fname) != "":
self.lastPath = os.path.abspath(os.path.join(str(fname), os.pardir))
GUI.JobList.addItem(fname)
def clearJobs(self):
@@ -884,19 +889,19 @@ class KCCGUI(KCC_ui.Ui_KCC):
self.settings.setValue('currentFormat', GUI.FormatBox.currentIndex())
self.settings.setValue('currentMode', self.currentMode)
self.settings.setValue('firstStart', False)
self.settings.setValue('options', QtCore.QVariant({'MangaBox': GUI.MangaBox.checkState(),
'RotateBox': GUI.RotateBox.checkState(),
'QualityBox': GUI.QualityBox.checkState(),
'ProcessingBox': GUI.ProcessingBox.checkState(),
'UpscaleBox': GUI.UpscaleBox.checkState(),
'NoRotateBox': GUI.NoRotateBox.checkState(),
'BorderBox': GUI.BorderBox.checkState(),
'WebtoonBox': GUI.WebtoonBox.checkState(),
'NoDitheringBox': GUI.NoDitheringBox.checkState(),
'ColorBox': GUI.ColorBox.checkState(),
'customWidth': GUI.customWidth.text(),
'customHeight': GUI.customHeight.text(),
'GammaSlider': float(self.GammaValue)*100}))
self.settings.setValue('options', {'MangaBox': GUI.MangaBox.checkState(),
'RotateBox': GUI.RotateBox.checkState(),
'QualityBox': GUI.QualityBox.checkState(),
'ProcessingBox': GUI.ProcessingBox.checkState(),
'UpscaleBox': GUI.UpscaleBox.checkState(),
'NoRotateBox': GUI.NoRotateBox.checkState(),
'BorderBox': GUI.BorderBox.checkState(),
'WebtoonBox': GUI.WebtoonBox.checkState(),
'NoDitheringBox': GUI.NoDitheringBox.checkState(),
'ColorBox': GUI.ColorBox.checkState(),
'customWidth': GUI.customWidth.text(),
'customHeight': GUI.customHeight.text(),
'GammaSlider': float(self.GammaValue)*100})
self.settings.sync()
def handleMessage(self, message):
@@ -947,8 +952,7 @@ class KCCGUI(KCC_ui.Ui_KCC):
self.currentMode = self.settings.value('currentMode', 1, type=int)
self.currentFormat = self.settings.value('currentFormat', 0, type=int)
self.firstStart = self.settings.value('firstStart', True, type=bool)
self.options = self.settings.value('options', QtCore.QVariant({'GammaSlider': 0}))
self.options = self.options.toPyObject()
self.options = self.settings.value('options', {'GammaSlider': 0})
self.worker = WorkerThread()
self.versionCheck = VersionThread()
self.contentServer = WebServerThread()
@@ -996,7 +1000,8 @@ class KCCGUI(KCC_ui.Ui_KCC):
formats = ['MOBI', 'EPUB', 'CBZ']
versionCheck = Popen('kindlegen -locale en', stdout=PIPE, stderr=STDOUT, shell=True)
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]
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='

View File

@@ -2,14 +2,14 @@
# Resource object code
#
# Created: N 6. paź 13:26:15 2013
# by: The Resource Compiler for PyQt (Qt v4.8.5)
# Created: mer nov 13 21:20:16 2013
# by: The Resource Compiler for PyQt (Qt v4.8.6)
#
# WARNING! All changes made in this file will be lost!
from PyQt4 import QtCore
qt_resource_data = "\
qt_resource_data = b"\
\x00\x00\x09\x59\
\x89\
\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\
"
qt_resource_name = "\
qt_resource_name = b"\
\x00\x07\
\x0a\xcc\xf9\x43\
\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\
"
qt_resource_struct = "\
qt_resource_struct = b"\
\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\x36\x00\x02\x00\x00\x00\x01\x00\x00\x00\x11\

View File

@@ -321,4 +321,4 @@ class Ui_KCC(object):
self.ActionBasic.setText(_translate("KCC", "Basic", None))
self.ActionAdvanced.setText(_translate("KCC", "Advanced", None))
import KCC_rc
from . import KCC_rc

View File

@@ -390,4 +390,4 @@ class Ui_KCC(object):
self.ActionBasic.setText(_translate("KCC", "Basic", None))
self.ActionAdvanced.setText(_translate("KCC", "Advanced", None))
import KCC_rc
from . import KCC_rc

View File

@@ -408,4 +408,4 @@ class Ui_KCC(object):
self.ActionBasic.setText(_translate("KCC", "Basic", None))
self.ActionAdvanced.setText(_translate("KCC", "Advanced", None))
import KCC_rc
from . import KCC_rc

View File

@@ -1,4 +1,4 @@
__version__ = '3.6'
__version__ = '4.0'
__license__ = 'ISC'
__copyright__ = '2012-2013, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@vulturis.eu>'
__docformat__ = 'restructuredtext en'

2
kcc/__main__.py Normal file
View File

@@ -0,0 +1,2 @@
from kcc.comic2ebook import main
main()

View File

@@ -21,7 +21,7 @@ __docformat__ = 'restructuredtext en'
import os
import zipfile
import rarfile
from . import rarfile
import locale
from subprocess import STDOUT, PIPE
from psutil import Popen
@@ -52,7 +52,7 @@ class CBxArchive:
elif f.endswith('/'):
try:
os.makedirs(os.path.join(targetdir, f))
except StandardError:
except Exception:
pass # the dir exists so we are going to extract the images only.
else:
filelist.append(f)
@@ -67,7 +67,7 @@ class CBxArchive:
elif f.endswith('/'):
try:
os.makedirs(os.path.join(targetdir, f))
except StandardError:
except Exception:
pass # the dir exists so we are going to extract the images only.
else:
filelist.append(f.encode(locale.getpreferredencoding()))
@@ -85,7 +85,7 @@ class CBxArchive:
raise OSError
def extract(self, targetdir):
print "\n" + targetdir + "\n"
print("\n" + targetdir + "\n")
if self.compressor == 'rar':
self.extractCBR(targetdir)
elif self.compressor == 'zip':

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python2
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# 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
# PERFORMANCE OF THIS SOFTWARE.
#
__version__ = '3.6'
__version__ = '4.0'
__license__ = 'ISC'
__copyright__ = '2012-2013, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@vulturis.eu>'
__docformat__ = 'restructuredtext en'
@@ -35,14 +35,15 @@ from optparse import OptionParser, OptionGroup
from multiprocessing import Pool, freeze_support
from xml.dom.minidom import parse
from uuid import uuid4
from slugify import slugify
try:
from PyQt4 import QtCore
except ImportError:
QtCore = None
import comic2panel
import image
import cbxarchive
import pdfjpgextract
from . import comic2panel
from . import image
from . import cbxarchive
from . import pdfjpgextract
def buildHTML(path, imgfile):
@@ -172,7 +173,6 @@ def buildHTML(path, imgfile):
def buildNCX(dstdir, title, chapters):
options.uuid = str(uuid4())
options.uuid = options.uuid.encode('utf-8')
ncxfile = os.path.join(dstdir, 'OEBPS', 'toc.ncx')
f = open(ncxfile, "w")
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=\"generated\" content=\"true\"/>\n",
"</head>\n",
"<docTitle><text>", title.encode('utf-8'), "</text></docTitle>\n",
"<docTitle><text>", title, "</text></docTitle>\n",
"<navMap>"
])
for chapter in chapters:
@@ -195,7 +195,7 @@ def buildNCX(dstdir, title, chapters):
title = os.path.basename(folder)
filename = getImageFileName(os.path.join(folder, chapter[1]))
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")
f.write("</navMap>\n</ncx>")
f.close()
@@ -216,11 +216,11 @@ 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.encode('utf-8'), "</dc:title>\n",
"<dc:title>", title, "</dc:title>\n",
"<dc:language>en-US</dc:language>\n",
"<dc:identifier id=\"BookID\" opf:scheme=\"UUID\">", options.uuid, "</dc:identifier>\n"])
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",
"<meta name=\"RegionMagnification\" content=\"true\"/>\n",
"<meta name=\"region-mag\" content=\"true\"/>\n",
@@ -356,9 +356,9 @@ def fileImgProcess(work):
dirpath = work[1]
opt = work[2]
if opt.verbose:
print "Optimizing " + afile + " for " + opt.profile
print("Optimizing " + afile + " for " + opt.profile)
else:
print ".",
print(".", end=' ')
img = image.ComicPage(os.path.join(dirpath, afile), opt.profileData)
if opt.quality == 2:
wipe = False
@@ -370,7 +370,7 @@ def fileImgProcess(work):
split = img.splitPage(dirpath, opt.righttoleft, opt.rotate)
if split is not None:
if opt.verbose:
print "Splitted " + afile
print("Splitted " + afile)
img0 = image.ComicPage(split[0], opt.profileData)
applyImgOptimization(img0, opt)
img0.saveToDir(dirpath, opt.forcepng, opt.forcecolor, wipe)
@@ -394,7 +394,9 @@ def fileImgProcess(work):
img2.rotated = True
applyImgOptimization(img2, opt, 0)
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])
@@ -565,7 +567,7 @@ def getWorkFolder(afile):
path = cbx.extract(workdir)
except OSError:
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)
else:
rmtree(workdir, True)
@@ -592,7 +594,7 @@ def checkComicInfo(path, originalPath):
if os.path.exists(xmlPath):
try:
xml = parse(xmlPath)
except StandardError:
except Exception:
os.remove(xmlPath)
return
options.authors = []
@@ -628,18 +630,14 @@ def checkComicInfo(path, originalPath):
os.remove(xmlPath)
def slugify(value):
# Normalizes string, converts to lowercase, removes non-alpha characters and converts spaces to hyphens.
if isinstance(value, str):
#noinspection PyArgumentList
value = unicodedata.normalize('NFKD', unicode(value, 'latin1')).encode('ascii', 'ignore')
elif isinstance(value, unicode):
value = unicodedata.normalize('NFKD', value).encode('ascii', 'ignore')
value = re.sub('[^\w\s\.-]', '', value).strip().lower()
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 slugify(value):
# # Normalizes string, converts to lowercase, removes non-alpha characters and converts spaces to hyphens.
# value = unicodedata.normalize('NFKD', value).encode('ascii', 'ignore')
# value = re.sub('[^\w\s\.-]', '', value).strip().lower()
# 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):
@@ -775,7 +773,7 @@ def preSplitDirectory(path):
mode = 0
else:
if filesNumber > 0:
print '\nWARNING: Automatic output splitting failed.'
print('\nWARNING: Automatic output splitting failed.')
if GUI:
GUI.emit(QtCore.SIGNAL("addMessage"), 'Automatic output splitting failed. <a href='
'"https://github.com/ciromattia/kcc/wiki'
@@ -790,7 +788,7 @@ def preSplitDirectory(path):
if len(dirs) != 0:
detectedSubSubdirectories = True
elif len(dirs) == 0 and detectedSubSubdirectories:
print '\nWARNING: Automatic output splitting failed.'
print('\nWARNING: Automatic output splitting failed.')
if GUI:
GUI.emit(QtCore.SIGNAL("addMessage"), 'Automatic output splitting failed. <a href='
'"https://github.com/ciromattia/kcc/wiki'
@@ -807,7 +805,7 @@ def preSplitDirectory(path):
# One level of subdirectories
mode = 1
if detectedFilesInSubdirectories and detectedSubSubdirectories:
print '\nWARNING: Automatic output splitting failed.'
print('\nWARNING: Automatic output splitting failed.')
if GUI:
GUI.emit(QtCore.SIGNAL("addMessage"), 'Automatic output splitting failed. <a href='
'"https://github.com/ciromattia/kcc/wiki'
@@ -827,12 +825,12 @@ def preSplitDirectory(path):
def Copyright():
print ('comic2ebook v%(__version__)s. '
'Written 2013 by Ciro Mattia Gonano and Pawel Jastrzebski.' % globals())
print(('comic2ebook v%(__version__)s. '
'Written 2013 by Ciro Mattia Gonano and Pawel Jastrzebski.' % globals()))
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()
@@ -916,7 +914,7 @@ def main(argv=None, qtGUI=None):
else:
comic2panel.main(['-y ' + str(image.ProfileData.Profiles[options.profile][1][1]), '-i', path], qtGUI)
if options.imgproc:
print "\nProcessing images..."
print("\nProcessing images...")
if GUI:
GUI.emit(QtCore.SIGNAL("progressBarTick"), 'status', 'Processing images')
dirImgProcess(path + "/OEBPS/Images/")
@@ -943,14 +941,14 @@ def main(argv=None, qtGUI=None):
options.title = options.baseTitle + ' [' + str(tomeNumber) + '/' + str(len(tomes)) + ']'
if options.cbzoutput:
# if CBZ output wanted, compress all images and return filepath
print "\nCreating CBZ file..."
print("\nCreating CBZ file...")
if len(tomes) > 1:
filepath.append(getOutputFilename(args[0], options.output, '.cbz', ' ' + str(tomeNumber)))
else:
filepath.append(getOutputFilename(args[0], options.output, '.cbz', ''))
make_archive(tome + '_comic', 'zip', tome + '/OEBPS/Images')
else:
print "\nCreating EPUB structure..."
print("\nCreating EPUB structure...")
genEpubStruct(tome)
# actually zip the ePub
if len(tomes) > 1:
@@ -1017,7 +1015,7 @@ def checkOptions():
options.quality = 0
# Kindle for Android profile require target resolution.
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)
# Override profile data
if options.customwidth != 0 or options.customheight != 0:

View File

@@ -18,7 +18,7 @@
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
#
__version__ = '3.6'
__version__ = '4.0'
__license__ = 'ISC'
__copyright__ = '2012-2013, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@vulturis.eu>'
__docformat__ = 'restructuredtext en'
@@ -32,26 +32,26 @@ try:
#noinspection PyUnresolvedReferences
from PIL import Image, ImageStat
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'):
#noinspection PyUnresolvedReferences
import Tkinter
import tkinter
#noinspection PyUnresolvedReferences
import tkMessageBox
importRoot = Tkinter.Tk()
import tkinter.messagebox
importRoot = tkinter.Tk()
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)
except ImportError:
print "ERROR: Pillow is not installed!"
print("ERROR: Pillow is not installed!")
if sys.platform.startswith('linux'):
#noinspection PyUnresolvedReferences
import Tkinter
import tkinter
#noinspection PyUnresolvedReferences
import tkMessageBox
importRoot = Tkinter.Tk()
import tkinter.messagebox
importRoot = tkinter.Tk()
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)
try:
from PyQt4 import QtCore
@@ -118,7 +118,7 @@ def splitImage(work):
# Harcoded opttions
threshold = 1.0
delta = 15
print ".",
print(".", end=' ')
fileExpanded = os.path.splitext(name)
filePath = os.path.join(path, name)
# Detect corrupted files
@@ -210,13 +210,13 @@ def splitImage(work):
str(pageNumber) + '.png'), 'PNG')
pageNumber += 1
os.remove(filePath)
except StandardError:
except Exception:
return str(sys.exc_info()[1])
def Copyright():
print ('comic2panel v%(__version__)s. '
'Written 2013 by Ciro Mattia Gonano and Pawel Jastrzebski.' % globals())
print(('comic2panel v%(__version__)s. '
'Written 2013 by Ciro Mattia Gonano and Pawel Jastrzebski.' % globals()))
def main(argv=None, qtGUI=None):
@@ -245,7 +245,7 @@ def main(argv=None, qtGUI=None):
if options.height > 0:
options.sourceDir = args[0]
options.targetDir = args[0] + "-Splitted"
print "\nSplitting images..."
print("\nSplitting images...")
if os.path.isdir(options.sourceDir):
rmtree(options.targetDir, True)
copytree(options.sourceDir, options.targetDir)

View File

@@ -26,26 +26,26 @@ try:
# noinspection PyUnresolvedReferences
from PIL import Image, ImageOps, ImageStat, ImageChops
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'):
#noinspection PyUnresolvedReferences
import Tkinter
import tkinter
#noinspection PyUnresolvedReferences
import tkMessageBox
importRoot = Tkinter.Tk()
import tkinter.messagebox
importRoot = tkinter.Tk()
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)
except ImportError:
print "ERROR: Pillow is not installed!"
print("ERROR: Pillow is not installed!")
if platform.startswith('linux'):
#noinspection PyUnresolvedReferences
import Tkinter
import tkinter
#noinspection PyUnresolvedReferences
import tkMessageBox
importRoot = Tkinter.Tk()
import tkinter.messagebox
importRoot = tkinter.Tk()
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)
@@ -287,10 +287,10 @@ class ComicPage:
ratioDev = float(self.size[0]) / float(self.size[1])
if (float(self.image.size[0]) / float(self.image.size[1])) < ratioDev:
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:
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))
if generateBorder:
if fill == 'white':

View File

@@ -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>
# Improvements Copyright (C) 2009-2012 P. Durrant, K. Hendricks, S. Siebert, fandrieu, DiapDealer, nickredding
# 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(datain[zerosecstart: secstart])
datalst.append(datain[secend:])
dataout = "".join(datalst)
return dataout
dataout = "".join(str(datalst)[1:-1])
return dataout.encode('utf-8')
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(datain[zerosecstart:firstsecstart])
datalst.append(datain[lastsecend:])
dataout = "".join(datalst)
return dataout
dataout = "".join(str(datalst)[1:-1])
return dataout.encode('utf-8')
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(secdata)
datalst.append(datain[secstart:])
dataout = "".join(datalst)
return dataout
dataout = "".join(str(datalst)[1:-1])
return dataout.encode('utf-8')
def insertsectionrange(sectionsource, firstsec, lastsec, sectiontarget, targetsec): # insert a range of sections
dataout = sectiontarget
for idx in range(lastsec, firstsec-1, -1):
print(dataout)
dataout = insertsection(dataout, targetsec, readsection(sectionsource, idx))
return dataout
@@ -381,4 +385,10 @@ class mobi_split:
raise
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)

View File

@@ -63,7 +63,7 @@ class PdfJpgExtract:
istart += startfix
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]
jpgfile = file(self.path + "/jpg%d.jpg" % njpg, "wb")
jpgfile.write(jpg)

View File

@@ -633,7 +633,7 @@ class RarFile(object):
def printdir(self):
"""Print archive file list to stdout."""
for f in self._info_list:
print(f.filename)
print((f.filename))
def extract(self, member, path=None, pwd=None):
"""Extract single file into current directory.
@@ -1138,7 +1138,7 @@ class RarFile(object):
if self._crc_check:
crc = crc32(cmt)
if crc < 0:
crc += (long(1) << 32)
crc += (int(1) << 32)
if crc != inf.CRC:
return None
@@ -1342,7 +1342,7 @@ class RarExtFile(RawIOBase):
raise BadRarFile("Failed the read enough data")
crc = self.CRC
if crc < 0:
crc += (long(1) << 32)
crc += (int(1) << 32)
if crc != self.inf.CRC:
raise BadRarFile("Corrupt file - CRC check failed: " + self.inf.filename)

4
requirements.txt Normal file
View File

@@ -0,0 +1,4 @@
Pillow==2.2.1
Unidecode==0.04.14
psutil==1.1.3
python-slugify==0.0.6

View File

@@ -11,7 +11,7 @@ Usage (Windows):
from sys import platform
NAME = "KindleComicConverter"
VERSION = "3.6"
VERSION = "4.0"
MAIN = "kcc.py"
if platform == "darwin":
@@ -72,7 +72,7 @@ elif platform == "win32":
appendScriptToLibrary=False,
compress=True)])
else:
print 'Please use setup.sh to build Linux package.'
print('Please use setup.sh to build Linux package.')
exit()
#noinspection PyUnboundLocalVariable
@@ -91,5 +91,5 @@ setup(
if platform == "darwin":
from os import chmod
chmod('dist/' + NAME + '.app/Contents/Resources/unrar', 0777)
chmod('dist/' + NAME + '.app/Contents/Resources/7za', 0777)
chmod('dist/' + NAME + '.app/Contents/Resources/unrar', 0o777)
chmod('dist/' + NAME + '.app/Contents/Resources/7za', 0o777)

View File

@@ -1,7 +1,7 @@
#!/bin/bash
# Linux Python package build script
VERSION="3.6"
VERSION="4.0"
cp kcc.py __main__.py
zip kcc.zip __main__.py kcc/*.py