diff options
-rw-r--r-- | kcc.iss | 2 | ||||
-rw-r--r-- | kcc.py | 12 | ||||
-rw-r--r-- | kcc/KCC_gui.py | 181 | ||||
-rw-r--r-- | kcc/KCC_rc.py | 10 | ||||
-rw-r--r-- | kcc/KCC_ui.py | 2 | ||||
-rw-r--r-- | kcc/KCC_ui_linux.py | 2 | ||||
-rw-r--r-- | kcc/KCC_ui_osx.py | 2 | ||||
-rw-r--r-- | kcc/__init__.py | 2 | ||||
-rw-r--r-- | kcc/__main__.py | 2 | ||||
-rw-r--r-- | kcc/cbxarchive.py | 8 | ||||
-rwxr-xr-x | kcc/comic2ebook.py | 76 | ||||
-rw-r--r-- | kcc/comic2panel.py | 32 | ||||
-rwxr-xr-x | kcc/image.py | 24 | ||||
-rw-r--r-- | kcc/kindlesplit.py | 24 | ||||
-rw-r--r-- | kcc/pdfjpgextract.py | 2 | ||||
-rw-r--r-- | kcc/rarfile.py | 6 | ||||
-rw-r--r-- | requirements.txt | 4 | ||||
-rw-r--r-- | setup.py | 8 | ||||
-rw-r--r-- | setup.sh | 2 |
19 files changed, 210 insertions, 191 deletions
diff --git a/kcc.iss b/kcc.iss index fe6b807..7d5bffd 100644 --- a/kcc.iss +++ b/kcc.iss @@ -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" diff --git a/kcc.py b/kcc.py index 4d60f5e..a6f9c23 100644 --- a/kcc.py +++ b/kcc.py @@ -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 diff --git a/kcc/KCC_gui.py b/kcc/KCC_gui.py index 3713f65..0142767 100644 --- a/kcc/KCC_gui.py +++ b/kcc/KCC_gui.py @@ -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=' diff --git a/kcc/KCC_rc.py b/kcc/KCC_rc.py index 844ad65..f7307d2 100644 --- a/kcc/KCC_rc.py +++ b/kcc/KCC_rc.py @@ -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\ diff --git a/kcc/KCC_ui.py b/kcc/KCC_ui.py index a491c89..65c71a6 100644 --- a/kcc/KCC_ui.py +++ b/kcc/KCC_ui.py @@ -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 diff --git a/kcc/KCC_ui_linux.py b/kcc/KCC_ui_linux.py index 9fbdea3..c99227d 100644 --- a/kcc/KCC_ui_linux.py +++ b/kcc/KCC_ui_linux.py @@ -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 diff --git a/kcc/KCC_ui_osx.py b/kcc/KCC_ui_osx.py index c0910b8..175a3c4 100644 --- a/kcc/KCC_ui_osx.py +++ b/kcc/KCC_ui_osx.py @@ -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 diff --git a/kcc/__init__.py b/kcc/__init__.py index 506ea76..ca08060 100644 --- a/kcc/__init__.py +++ b/kcc/__init__.py @@ -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' \ No newline at end of file diff --git a/kcc/__main__.py b/kcc/__main__.py new file mode 100644 index 0000000..03034f1 --- /dev/null +++ b/kcc/__main__.py @@ -0,0 +1,2 @@ +from kcc.comic2ebook import main +main() \ No newline at end of file diff --git a/kcc/cbxarchive.py b/kcc/cbxarchive.py index e083d28..ae70a0a 100644 --- a/kcc/cbxarchive.py +++ b/kcc/cbxarchive.py @@ -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': diff --git a/kcc/comic2ebook.py b/kcc/comic2ebook.py index 09e5ad9..f54e28e 100755 --- a/kcc/comic2ebook.py +++ b/kcc/comic2ebook.py @@ -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: diff --git a/kcc/comic2panel.py b/kcc/comic2panel.py index d194acd..787eec8 100644 --- a/kcc/comic2panel.py +++ b/kcc/comic2panel.py @@ -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) diff --git a/kcc/image.py b/kcc/image.py index 3c80d74..1174eb2 100755 --- a/kcc/image.py +++ b/kcc/image.py @@ -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': diff --git a/kcc/kindlesplit.py b/kcc/kindlesplit.py index c8ae74d..c74ff95 100644 --- a/kcc/kindlesplit.py +++ b/kcc/kindlesplit.py @@ -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 \ No newline at end of file + return self.result_file + + +if __name__ == "__main__": + import sys + mobi_split(sys.argv[1], False) + sys.exit(0) diff --git a/kcc/pdfjpgextract.py b/kcc/pdfjpgextract.py index d9dad09..76f8a0e 100644 --- a/kcc/pdfjpgextract.py +++ b/kcc/pdfjpgextract.py @@ -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) diff --git a/kcc/rarfile.py b/kcc/rarfile.py index d7340ae..fe7db2a 100644 --- a/kcc/rarfile.py +++ b/kcc/rarfile.py @@ -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) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..264dcd4 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,4 @@ +Pillow==2.2.1 +Unidecode==0.04.14 +psutil==1.1.3 +python-slugify==0.0.6 diff --git a/setup.py b/setup.py index ace85f9..149cb48 100644 --- a/setup.py +++ b/setup.py @@ -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) \ No newline at end of file + chmod('dist/' + NAME + '.app/Contents/Resources/unrar', 0o777) + chmod('dist/' + NAME + '.app/Contents/Resources/7za', 0o777) \ No newline at end of file diff --git a/setup.sh b/setup.sh index a36d7f0..f4382d1 100644 --- a/setup.sh +++ b/setup.sh @@ -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 |