about summary refs log tree commit diff
diff options
context:
space:
mode:
-rwxr-xr-xkcc-c2e.py4
-rwxr-xr-xkcc-c2p.py4
-rw-r--r--kcc/KCC_gui.py5
-rwxr-xr-xkcc/comic2ebook.py742
-rw-r--r--kcc/comic2panel.py12
5 files changed, 364 insertions, 403 deletions
diff --git a/kcc-c2e.py b/kcc-c2e.py
index 4a6442f..e6c1f59 100755
--- a/kcc-c2e.py
+++ b/kcc-c2e.py
@@ -63,10 +63,10 @@ if len(missing) > 0:
     exit(1)
 
 from multiprocessing import freeze_support
-from kcc.comic2ebook import main, Copyright
+from kcc.comic2ebook import main
 
 if __name__ == "__main__":
     freeze_support()
-    Copyright()
+    print(('comic2ebook v%(__version__)s. Written by Ciro Mattia Gonano and Pawel Jastrzebski.' % globals()))
     main(sys.argv[1:])
     sys.exit(0)
\ No newline at end of file
diff --git a/kcc-c2p.py b/kcc-c2p.py
index 3976e2e..cc272ad 100755
--- a/kcc-c2p.py
+++ b/kcc-c2p.py
@@ -51,10 +51,10 @@ if len(missing) > 0:
     exit(1)
 
 from multiprocessing import freeze_support
-from kcc.comic2panel import main, Copyright
+from kcc.comic2panel import main
 
 if __name__ == "__main__":
     freeze_support()
-    Copyright()
+    print(('comic2ebook v%(__version__)s. Written by Ciro Mattia Gonano and Pawel Jastrzebski.' % globals()))
     main(sys.argv[1:])
     sys.exit(0)
\ No newline at end of file
diff --git a/kcc/KCC_gui.py b/kcc/KCC_gui.py
index 1102067..1161491 100644
--- a/kcc/KCC_gui.py
+++ b/kcc/KCC_gui.py
@@ -196,7 +196,6 @@ class VersionThread(QtCore.QThread):
 
     def run(self):
         try:
-            sleep(1)
             XML = urlopen('http://kcc.iosphe.re/Version.php')
             XML = parse(XML)
         except Exception:
@@ -493,7 +492,6 @@ class WorkerThread(QtCore.QThread):
                         worker.signals.result.connect(self.addResult)
                         self.pool.start(worker)
                     self.pool.waitForDone()
-                    sleep(0.5)
                     self.kindlegenErrorCode = [0]
                     for errors in self.workerOutput:
                         if errors[0] != 0:
@@ -503,7 +501,6 @@ class WorkerThread(QtCore.QThread):
                         for item in outputPath:
                             if os.path.exists(item):
                                 os.remove(item)
-                            sleep(1)
                             if os.path.exists(item.replace('.epub', '.mobi')):
                                 os.remove(item.replace('.epub', '.mobi'))
                         self.clean()
@@ -521,7 +518,6 @@ class WorkerThread(QtCore.QThread):
                             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
@@ -555,7 +551,6 @@ class WorkerThread(QtCore.QThread):
                         for item in outputPath:
                             if os.path.exists(item):
                                 os.remove(item)
-                            sleep(1)
                             if os.path.exists(item.replace('.epub', '.mobi')):
                                 os.remove(item.replace('.epub', '.mobi'))
                         MW.addMessage.emit('KindleGen failed to create MOBI!', 'error', False)
diff --git a/kcc/comic2ebook.py b/kcc/comic2ebook.py
index c654071..81145b5 100755
--- a/kcc/comic2ebook.py
+++ b/kcc/comic2ebook.py
@@ -47,24 +47,36 @@ from . import cbxarchive
 from . import pdfjpgextract
 
 
+def main(argv=None):
+    global options
+    parser = makeParser()
+    options, args = parser.parse_args(argv)
+    checkOptions()
+    if len(args) != 1:
+        parser.print_help()
+        return
+    outputPath = makeBook(args[0])
+    return outputPath
+
+
 def buildHTML(path, imgfile, imgfilepath):
     imgfilepath = md5Checksum(imgfilepath)
     filename = getImageFileName(imgfile)
     if filename is not None:
         if options.imgproc:
-            if "Rotated" in theGreatIndex[imgfilepath]:
+            if "Rotated" in options.imgIndex[imgfilepath]:
                 rotatedPage = True
             else:
                 rotatedPage = False
-            if "NoPanelView" in theGreatIndex[imgfilepath]:
+            if "NoPanelView" in options.imgIndex[imgfilepath]:
                 noPV = True
             else:
                 noPV = False
-            if "NoHorizontalPanelView" in theGreatIndex[imgfilepath]:
+            if "NoHorizontalPanelView" in options.imgIndex[imgfilepath]:
                 noHorizontalPV = True
             else:
                 noHorizontalPV = False
-            if "NoVerticalPanelView" in theGreatIndex[imgfilepath]:
+            if "NoVerticalPanelView" in options.imgIndex[imgfilepath]:
                 noVerticalPV = True
             else:
                 noVerticalPV = False
@@ -146,7 +158,7 @@ def buildHTML(path, imgfile, imgfilepath):
                 imgfilepv = ".".join(imgfilepv)
             else:
                 imgfilepv = imgfile
-            xl, yu, xr, yd = checkMargins(imgfilepath)
+            xl, yu, xr, yd = detectMargins(imgfilepath)
             boxStyles = {"BoxTL": "left:" + xl + ";top:" + yu + ";",
                          "BoxTR": "right:" + xr + ";top:" + yu + ";",
                          "BoxBL": "left:" + xl + ";bottom:" + yd + ";",
@@ -168,35 +180,6 @@ def buildHTML(path, imgfile, imgfilepath):
         return path, imgfile
 
 
-def checkMargins(path):
-    if options.imgproc:
-        for flag in theGreatIndex[path]:
-            if "Margins-" in flag:
-                flag = flag.split('-')
-                xl = flag[1]
-                yu = flag[2]
-                xr = flag[3]
-                yd = flag[4]
-                if xl != "0":
-                    xl = "-" + str(float(xl)/100) + "%"
-                else:
-                    xl = "0%"
-                if xr != "0":
-                    xr = "-" + str(float(xr)/100) + "%"
-                else:
-                    xr = "0%"
-                if yu != "0":
-                    yu = "-" + str(float(yu)/100) + "%"
-                else:
-                    yu = "0%"
-                if yd != "0":
-                    yd = "-" + str(float(yd)/100) + "%"
-                else:
-                    yd = "0%"
-                return xl, yu, xr, yd
-    return '0%', '0%', '0%', '0%'
-
-
 def buildNCX(dstdir, title, chapters, chapterNames):
     options.uuid = str(uuid4())
     ncxfile = os.path.join(dstdir, 'OEBPS', 'toc.ncx')
@@ -305,133 +288,7 @@ def buildOPF(dstdir, title, filelist, cover=None):
     f.close()
 
 
-def applyImgOptimization(img, opt, hqImage=None):
-    if not img.fill:
-        img.getImageFill(opt.webtoon)
-    if not opt.webtoon:
-        img.cropWhiteSpace()
-    if opt.cutpagenumbers and not opt.webtoon:
-        img.cutPageNumber()
-    img.optimizeImage(opt.gamma)
-    if hqImage:
-        img.resizeImage(opt.upscale, opt.stretch, opt.bordersColor, 0)
-        img.calculateBorder(hqImage, True)
-    else:
-        img.resizeImage(opt.upscale, opt.stretch, opt.bordersColor, opt.quality)
-        if opt.panelview:
-            if opt.quality == 0:
-                img.calculateBorder(img)
-            elif opt.quality == 1:
-                img.calculateBorder(img, True)
-    if opt.forcepng and not opt.forcecolor:
-        img.quantizeImage()
-
-
-def dirImgProcess(path):
-    global workerPool, workerOutput, theGreatIndex, theGreatWipe
-    workerPool = Pool()
-    workerOutput = []
-    work = []
-    theGreatIndex = {}
-    theGreatWipe = []
-    pagenumber = 0
-    for (dirpath, dirnames, filenames) in os.walk(path):
-        for afile in filenames:
-            if getImageFileName(afile) is not None:
-                pagenumber += 1
-                work.append([afile, dirpath, options])
-    if GUI:
-        GUI.progressBarTick.emit(str(pagenumber))
-    if len(work) > 0:
-        for i in work:
-            workerPool.apply_async(func=fileImgProcess, args=(i, ), callback=fileImgProcess_tick)
-        workerPool.close()
-        workerPool.join()
-        if GUI and not GUI.conversionAlive:
-            rmtree(os.path.join(path, '..', '..'), True)
-            raise UserWarning("Conversion interrupted.")
-        if len(workerOutput) > 0:
-            rmtree(os.path.join(path, '..', '..'), True)
-            raise RuntimeError("One of workers crashed. Cause: " + workerOutput[0])
-        for file in theGreatWipe:
-            if os.path.isfile(file):
-                os.remove(file)
-    else:
-        rmtree(os.path.join(path, '..', '..'), True)
-        raise UserWarning("Source directory is empty.")
-
-
-def fileImgProcess_tick(output):
-    if isinstance(output, str):
-        workerOutput.append(output)
-        workerPool.terminate()
-    else:
-        for page in output:
-            if page is not None:
-                if isinstance(page, str):
-                    theGreatWipe.append(page)
-                else:
-                    theGreatIndex[page[0]] = page[1]
-    if GUI:
-        GUI.progressBarTick.emit('tick')
-        if not GUI.conversionAlive:
-            workerPool.terminate()
-
-
-def fileImgProcess(work):
-    try:
-        afile = work[0]
-        dirpath = work[1]
-        opt = work[2]
-        output = []
-        img = image.ComicPage(os.path.join(dirpath, afile), opt.profileData)
-        if opt.quality == 2:
-            wipe = False
-        else:
-            wipe = True
-        if opt.nosplitrotate:
-            splitter = None
-        else:
-            splitter = img.splitPage(dirpath, opt.righttoleft, opt.rotate)
-        if splitter is not None:
-            img0 = image.ComicPage(splitter[0], opt.profileData)
-            applyImgOptimization(img0, opt)
-            output.append(img0.saveToDir(dirpath, opt.forcepng, opt.forcecolor))
-            img1 = image.ComicPage(splitter[1], opt.profileData)
-            applyImgOptimization(img1, opt)
-            output.append(img1.saveToDir(dirpath, opt.forcepng, opt.forcecolor))
-            if wipe:
-                output.append(img0.origFileName)
-                output.append(img1.origFileName)
-            if opt.quality == 2:
-                img0b = image.ComicPage(splitter[0], opt.profileData, img0.fill)
-                applyImgOptimization(img0b, opt, img0)
-                output.append(img0b.saveToDir(dirpath, opt.forcepng, opt.forcecolor))
-                img1b = image.ComicPage(splitter[1], opt.profileData, img1.fill)
-                applyImgOptimization(img1b, opt, img1)
-                output.append(img1b.saveToDir(dirpath, opt.forcepng, opt.forcecolor))
-                output.append(img0.origFileName)
-                output.append(img1.origFileName)
-            output.append(img.origFileName)
-        else:
-            applyImgOptimization(img, opt)
-            output.append(img.saveToDir(dirpath, opt.forcepng, opt.forcecolor))
-            if wipe:
-                output.append(img.origFileName)
-            if opt.quality == 2:
-                img2 = image.ComicPage(os.path.join(dirpath, afile), opt.profileData, img.fill)
-                if img.rotated:
-                    img2.image = img2.image.rotate(90)
-                    img2.rotated = True
-                applyImgOptimization(img2, opt, img)
-                output.append(img2.saveToDir(dirpath, opt.forcepng, opt.forcecolor))
-                output.append(img.origFileName)
-        return output
-    except Exception:
-        return str(sys.exc_info()[1])
-
-
-def genEpubStruct(path, chapterNames):
+def buildEPUB(path, chapterNames):
     filelist = []
     chapterlist = []
     cover = None
@@ -568,6 +425,132 @@ def genEpubStruct(path, chapterNames):
     buildOPF(path, options.title, filelist, cover)
 
 
+def imgOptimization(img, opt, hqImage=None):
+    if not img.fill:
+        img.getImageFill(opt.webtoon)
+    if not opt.webtoon:
+        img.cropWhiteSpace()
+    if opt.cutpagenumbers and not opt.webtoon:
+        img.cutPageNumber()
+    img.optimizeImage(opt.gamma)
+    if hqImage:
+        img.resizeImage(opt.upscale, opt.stretch, opt.bordersColor, 0)
+        img.calculateBorder(hqImage, True)
+    else:
+        img.resizeImage(opt.upscale, opt.stretch, opt.bordersColor, opt.quality)
+        if opt.panelview:
+            if opt.quality == 0:
+                img.calculateBorder(img)
+            elif opt.quality == 1:
+                img.calculateBorder(img, True)
+    if opt.forcepng and not opt.forcecolor:
+        img.quantizeImage()
+
+
+def imgDirectoryProcessing(path):
+    global workerPool, workerOutput
+    workerPool = Pool()
+    workerOutput = []
+    options.imgIndex = {}
+    options.imgPurgeIndex = []
+    work = []
+    pagenumber = 0
+    for (dirpath, dirnames, filenames) in os.walk(path):
+        for afile in filenames:
+            if getImageFileName(afile) is not None:
+                pagenumber += 1
+                work.append([afile, dirpath, options])
+    if GUI:
+        GUI.progressBarTick.emit(str(pagenumber))
+    if len(work) > 0:
+        for i in work:
+            workerPool.apply_async(func=imgFileProcessing, args=(i, ), callback=imgFileProcessingTick)
+        workerPool.close()
+        workerPool.join()
+        if GUI and not GUI.conversionAlive:
+            rmtree(os.path.join(path, '..', '..'), True)
+            raise UserWarning("Conversion interrupted.")
+        if len(workerOutput) > 0:
+            rmtree(os.path.join(path, '..', '..'), True)
+            raise RuntimeError("One of workers crashed. Cause: " + workerOutput[0])
+        for file in options.imgPurgeIndex:
+            if os.path.isfile(file):
+                os.remove(file)
+    else:
+        rmtree(os.path.join(path, '..', '..'), True)
+        raise UserWarning("Source directory is empty.")
+
+
+def imgFileProcessingTick(output):
+    if isinstance(output, str):
+        workerOutput.append(output)
+        workerPool.terminate()
+    else:
+        for page in output:
+            if page is not None:
+                if isinstance(page, str):
+                    options.imgPurgeIndex.append(page)
+                else:
+                    options.imgIndex[page[0]] = page[1]
+    if GUI:
+        GUI.progressBarTick.emit('tick')
+        if not GUI.conversionAlive:
+            workerPool.terminate()
+
+
+def imgFileProcessing(work):
+    try:
+        afile = work[0]
+        dirpath = work[1]
+        opt = work[2]
+        output = []
+        img = image.ComicPage(os.path.join(dirpath, afile), opt.profileData)
+        if opt.quality == 2:
+            wipe = False
+        else:
+            wipe = True
+        if opt.nosplitrotate:
+            splitter = None
+        else:
+            splitter = img.splitPage(dirpath, opt.righttoleft, opt.rotate)
+        if splitter is not None:
+            img0 = image.ComicPage(splitter[0], opt.profileData)
+            imgOptimization(img0, opt)
+            output.append(img0.saveToDir(dirpath, opt.forcepng, opt.forcecolor))
+            img1 = image.ComicPage(splitter[1], opt.profileData)
+            imgOptimization(img1, opt)
+            output.append(img1.saveToDir(dirpath, opt.forcepng, opt.forcecolor))
+            if wipe:
+                output.append(img0.origFileName)
+                output.append(img1.origFileName)
+            if opt.quality == 2:
+                img0b = image.ComicPage(splitter[0], opt.profileData, img0.fill)
+                imgOptimization(img0b, opt, img0)
+                output.append(img0b.saveToDir(dirpath, opt.forcepng, opt.forcecolor))
+                img1b = image.ComicPage(splitter[1], opt.profileData, img1.fill)
+                imgOptimization(img1b, opt, img1)
+                output.append(img1b.saveToDir(dirpath, opt.forcepng, opt.forcecolor))
+                output.append(img0.origFileName)
+                output.append(img1.origFileName)
+            output.append(img.origFileName)
+        else:
+            imgOptimization(img, opt)
+            output.append(img.saveToDir(dirpath, opt.forcepng, opt.forcecolor))
+            if wipe:
+                output.append(img.origFileName)
+            if opt.quality == 2:
+                img2 = image.ComicPage(os.path.join(dirpath, afile), opt.profileData, img.fill)
+                if img.rotated:
+                    img2.image = img2.image.rotate(90)
+                    img2.rotated = True
+                imgOptimization(img2, opt, img)
+                output.append(img2.saveToDir(dirpath, opt.forcepng, opt.forcecolor))
+                output.append(img.origFileName)
+        return output
+    except Exception:
+        return str(sys.exc_info()[1])
+
+
 def getWorkFolder(afile):
     if len(afile) > 240:
         raise UserWarning("Path is too long.")
@@ -579,7 +562,7 @@ def getWorkFolder(afile):
             if len(fullPath) > 240:
                 raise UserWarning("Path is too long.")
             copytree(afile, fullPath)
-            sanitizeTreeBeforeConversion(fullPath)
+            sanitizePermissions(fullPath)
             return workdir
         except OSError:
             rmtree(workdir, True)
@@ -609,7 +592,33 @@ def getWorkFolder(afile):
     return path
 
 
-def checkComicInfo(path, originalPath):
+def getOutputFilename(srcpath, wantedname, ext, tomeNumber):
+    if srcpath[-1] == os.path.sep:
+        srcpath = srcpath[:-1]
+    if not ext.startswith('.'):
+        ext = '.' + ext
+    if wantedname is not None:
+        if wantedname.endswith(ext):
+            filename = os.path.abspath(wantedname)
+        elif os.path.isdir(srcpath):
+            filename = os.path.join(os.path.abspath(options.output), os.path.basename(srcpath) + ext)
+        else:
+            filename = os.path.join(os.path.abspath(options.output),
+                                    os.path.basename(os.path.splitext(srcpath)[0]) + ext)
+    elif os.path.isdir(srcpath):
+        filename = srcpath + tomeNumber + ext
+    else:
+        filename = os.path.splitext(srcpath)[0] + tomeNumber + ext
+    if os.path.isfile(filename):
+        counter = 0
+        basename = os.path.splitext(filename)[0]
+        while os.path.isfile(basename + '_kcc' + str(counter) + ext):
+            counter += 1
+        filename = basename + '_kcc' + str(counter) + ext
+    return filename
+
+
+def getComicInfo(path, originalPath):
     xmlPath = os.path.join(path, 'ComicInfo.xml')
     options.authors = ['KCC']
     titleSuffix = ''
@@ -660,45 +669,42 @@ def checkComicInfo(path, originalPath):
         os.remove(xmlPath)
 
 
-def slugify(value):
-    value = slugifyExt(value)
-    value = sub(r'0*([0-9]{4,})', r'\1', sub(r'([0-9]+)', r'0000\1', value))
-    return value
+def getDirectorySize(start_path='.'):
+    total_size = 0
+    for dirpath, dirnames, filenames in os.walk(start_path):
+        for f in filenames:
+            fp = os.path.join(dirpath, f)
+            total_size += os.path.getsize(fp)
+    return total_size
 
 
 def sanitizeTree(filetree):
     chapterNames = {}
     for root, dirs, files in os.walk(filetree, False):
         for name in files:
-            if name.startswith('.') or name.lower() == 'thumbs.db':
-                os.remove(os.path.join(root, name))
-            else:
-                splitname = os.path.splitext(name)
-                slugified = slugify(splitname[0])
-                while os.path.exists(os.path.join(root, slugified + splitname[1])) and splitname[0].upper()\
-                        != slugified.upper():
-                    slugified += "A"
-                newKey = os.path.join(root, slugified + splitname[1])
-                key = os.path.join(root, name)
-                if key != newKey:
-                    os.replace(key, newKey)
+            splitname = os.path.splitext(name)
+            slugified = slugify(splitname[0])
+            while os.path.exists(os.path.join(root, slugified + splitname[1])) and splitname[0].upper()\
+                    != slugified.upper():
+                slugified += "A"
+            newKey = os.path.join(root, slugified + splitname[1])
+            key = os.path.join(root, name)
+            if key != newKey:
+                os.replace(key, newKey)
         for name in dirs:
-            if name.startswith('.'):
-                os.remove(os.path.join(root, name))
-            else:
-                tmpName = name
-                slugified = slugify(name)
-                while os.path.exists(os.path.join(root, slugified)) and name.upper() != slugified.upper():
-                    slugified += "A"
-                chapterNames[slugified] = tmpName
-                newKey = os.path.join(root, slugified)
-                key = os.path.join(root, name)
-                if key != newKey:
-                    os.replace(key, newKey)
+            tmpName = name
+            slugified = slugify(name)
+            while os.path.exists(os.path.join(root, slugified)) and name.upper() != slugified.upper():
+                slugified += "A"
+            chapterNames[slugified] = tmpName
+            newKey = os.path.join(root, slugified)
+            key = os.path.join(root, name)
+            if key != newKey:
+                os.replace(key, newKey)
     return chapterNames
 
 
-def sanitizeTreeBeforeConversion(filetree):
+def sanitizePermissions(filetree):
     for root, dirs, files in os.walk(filetree, False):
         for name in files:
             os.chmod(os.path.join(root, name), S_IWRITE | S_IREAD)
@@ -706,23 +712,66 @@ def sanitizeTreeBeforeConversion(filetree):
             os.chmod(os.path.join(root, name), S_IWRITE | S_IREAD | S_IEXEC)
 
 
-def getDirectorySize(start_path='.'):
-    total_size = 0
-    for dirpath, dirnames, filenames in os.walk(start_path):
-        for f in filenames:
-            fp = os.path.join(dirpath, f)
-            total_size += os.path.getsize(fp)
-    return total_size
-
-
-def createNewTome():
-    tomePathRoot = mkdtemp('', 'KCC-TMP-')
-    tomePath = os.path.join(tomePathRoot, 'OEBPS', 'Images')
-    os.makedirs(tomePath)
-    return tomePath, tomePathRoot
+#noinspection PyUnboundLocalVariable
+def splitDirectory(path):
+    # Detect directory stucture
+    for root, dirs, files in walkLevel(os.path.join(path, 'OEBPS', 'Images'), 0):
+        subdirectoryNumber = len(dirs)
+        filesNumber = len(files)
+    if subdirectoryNumber == 0:
+        # No subdirectories
+        mode = 0
+    else:
+        if filesNumber > 0:
+            print('\nWARNING: Automatic output splitting failed.')
+            if GUI:
+                GUI.addMessage.emit('Automatic output splitting failed. <a href='
+                                    '"https://github.com/ciromattia/kcc/wiki'
+                                    '/Automatic-output-splitting">'
+                                    'More details.</a>', 'warning', False)
+                GUI.addMessage.emit('', '', False)
+            return [path]
+        detectedSubSubdirectories = False
+        detectedFilesInSubdirectories = False
+        for root, dirs, files in walkLevel(os.path.join(path, 'OEBPS', 'Images'), 1):
+            if root != os.path.join(path, 'OEBPS', 'Images'):
+                if len(dirs) != 0:
+                    detectedSubSubdirectories = True
+                elif len(dirs) == 0 and detectedSubSubdirectories:
+                    print('\nWARNING: Automatic output splitting failed.')
+                    if GUI:
+                        GUI.addMessage.emit('Automatic output splitting failed. <a href='
+                                            '"https://github.com/ciromattia/kcc/wiki'
+                                            '/Automatic-output-splitting">'
+                                            'More details.</a>', 'warning', False)
+                        GUI.addMessage.emit('', '', False)
+                    return [path]
+                if len(files) != 0:
+                    detectedFilesInSubdirectories = True
+        if detectedSubSubdirectories:
+            # Two levels of subdirectories
+            mode = 2
+        else:
+            # One level of subdirectories
+            mode = 1
+        if detectedFilesInSubdirectories and detectedSubSubdirectories:
+            print('\nWARNING: Automatic output splitting failed.')
+            if GUI:
+                GUI.addMessage.emit('Automatic output splitting failed. <a href='
+                                    '"https://github.com/ciromattia/kcc/wiki'
+                                    '/Automatic-output-splitting">'
+                                    'More details.</a>', 'warning', False)
+                GUI.addMessage.emit('', '', False)
+            return [path]
+    # Split directories
+    splitter = splitProcess(os.path.join(path, 'OEBPS', 'Images'), mode)
+    path = [path]
+    for tome in splitter:
+        path.append(tome)
+    return path
 
 
-def splitDirectory(path, mode):
+def splitProcess(path, mode):
     output = []
     currentSize = 0
     currentTarget = path
@@ -783,65 +832,6 @@ def splitDirectory(path, mode):
     return output
 
 
-#noinspection PyUnboundLocalVariable
-def preSplitDirectory(path):
-    # Detect directory stucture
-    for root, dirs, files in walkLevel(os.path.join(path, 'OEBPS', 'Images'), 0):
-        subdirectoryNumber = len(dirs)
-        filesNumber = len(files)
-    if subdirectoryNumber == 0:
-        # No subdirectories
-        mode = 0
-    else:
-        if filesNumber > 0:
-            print('\nWARNING: Automatic output splitting failed.')
-            if GUI:
-                GUI.addMessage.emit('Automatic output splitting failed. <a href='
-                                    '"https://github.com/ciromattia/kcc/wiki'
-                                    '/Automatic-output-splitting">'
-                                    'More details.</a>', 'warning', False)
-                GUI.addMessage.emit('', '', False)
-            return [path]
-        detectedSubSubdirectories = False
-        detectedFilesInSubdirectories = False
-        for root, dirs, files in walkLevel(os.path.join(path, 'OEBPS', 'Images'), 1):
-            if root != os.path.join(path, 'OEBPS', 'Images'):
-                if len(dirs) != 0:
-                    detectedSubSubdirectories = True
-                elif len(dirs) == 0 and detectedSubSubdirectories:
-                    print('\nWARNING: Automatic output splitting failed.')
-                    if GUI:
-                        GUI.addMessage.emit('Automatic output splitting failed. <a href='
-                                            '"https://github.com/ciromattia/kcc/wiki'
-                                            '/Automatic-output-splitting">'
-                                            'More details.</a>', 'warning', False)
-                        GUI.addMessage.emit('', '', False)
-                    return [path]
-                if len(files) != 0:
-                    detectedFilesInSubdirectories = True
-        if detectedSubSubdirectories:
-            # Two levels of subdirectories
-            mode = 2
-        else:
-            # One level of subdirectories
-            mode = 1
-        if detectedFilesInSubdirectories and detectedSubSubdirectories:
-            print('\nWARNING: Automatic output splitting failed.')
-            if GUI:
-                GUI.addMessage.emit('Automatic output splitting failed. <a href='
-                                    '"https://github.com/ciromattia/kcc/wiki'
-                                    '/Automatic-output-splitting">'
-                                    'More details.</a>', 'warning', False)
-                GUI.addMessage.emit('', '', False)
-            return [path]
-    # Split directories
-    splitter = splitDirectory(os.path.join(path, 'OEBPS', 'Images'), mode)
-    path = [path]
-    for tome in splitter:
-        path.append(tome)
-    return path
-
-
 def detectCorruption(tmpPath, orgPath):
     for root, dirs, files in os.walk(tmpPath, False):
         for name in files:
@@ -861,6 +851,48 @@ def detectCorruption(tmpPath, orgPath):
                     raise RuntimeError('Image file %s is corrupted.' % pathOrg)
 
 
+def detectMargins(path):
+    if options.imgproc:
+        for flag in options.imgIndex[path]:
+            if "Margins-" in flag:
+                flag = flag.split('-')
+                xl = flag[1]
+                yu = flag[2]
+                xr = flag[3]
+                yd = flag[4]
+                if xl != "0":
+                    xl = "-" + str(float(xl)/100) + "%"
+                else:
+                    xl = "0%"
+                if xr != "0":
+                    xr = "-" + str(float(xr)/100) + "%"
+                else:
+                    xr = "0%"
+                if yu != "0":
+                    yu = "-" + str(float(yu)/100) + "%"
+                else:
+                    yu = "0%"
+                if yd != "0":
+                    yd = "-" + str(float(yd)/100) + "%"
+                else:
+                    yd = "0%"
+                return xl, yu, xr, yd
+    return '0%', '0%', '0%', '0%'
+
+
+def createNewTome():
+    tomePathRoot = mkdtemp('', 'KCC-TMP-')
+    tomePath = os.path.join(tomePathRoot, 'OEBPS', 'Images')
+    os.makedirs(tomePath)
+    return tomePath, tomePathRoot
+
+
+def slugify(value):
+    value = slugifyExt(value)
+    value = sub(r'0*([0-9]{4,})', r'\1', sub(r'([0-9]+)', r'0000\1', value))
+    return value
+
+
 def makeZIP(zipFilename, baseDir, isEPUB=False):
     zipFilename = os.path.abspath(zipFilename) + '.zip'
     zipOutput = ZipFile(zipFilename, 'w', ZIP_DEFLATED)
@@ -876,15 +908,6 @@ def makeZIP(zipFilename, baseDir, isEPUB=False):
     return zipFilename
 
 
-def Copyright():
-    print(('comic2ebook v%(__version__)s. Written by Ciro Mattia Gonano and Pawel Jastrzebski.' % globals()))
-
-
-def Usage():
-    print("Generates EPUB/CBZ comic ebook from a bunch of images.")
-    parser.print_help()
-
-
 def makeParser():
     """Create and return an option parser set up with kcc's options."""
     psr = OptionParser(usage="Usage: kcc-c2e [options] comic_file|comic_folder", add_help_option=False)
@@ -953,57 +976,89 @@ def makeParser():
     return psr
 
 
-def main(argv=None, qtGUI=None):
-    global parser, options, GUI
-    parser = makeParser()
-    options, args = parser.parse_args(argv)
-    checkOptions()
-    if qtGUI:
-        GUI = qtGUI
-        GUI.progressBarTick.emit('1')
+def checkOptions():
+    global options
+    options.panelview = True
+    options.bordersColor = None
+    if options.white_borders:
+        options.bordersColor = "white"
+    if options.black_borders:
+        options.bordersColor = "black"
+    # Disabling grayscale conversion for Kindle Fire family.
+    if options.profile == 'KF' or options.profile == 'KFHD' or options.profile == 'KFHD8' or options.profile == 'KFHDX'\
+       or options.profile == 'KFHDX8' or options.forcecolor:
+        options.forcecolor = True
     else:
-        GUI = None
-    if len(args) != 1:
-        parser.print_help()
-        return
-    outputPath = makeBook(args[0], qtGUI=qtGUI)
-    return outputPath
+        options.forcecolor = False
+    # Older Kindle don't need higher resolution files due lack of Panel View.
+    if options.profile == 'K1' or options.profile == 'K2' or options.profile == 'KDX':
+        options.quality = 0
+        options.panelview = False
+    # Webtoon mode mandatory options
+    if options.webtoon:
+        options.nosplitrotate = True
+        options.quality = 0
+        options.panelview = False
+    # Disable all Kindle features for other e-readers
+    if options.profile == 'OTHER':
+        options.panelview = False
+        options.quality = 0
+    if 'Ko' in options.profile:
+        options.panelview = False
+        # Kobo models can't use ultra quality mode
+        if options.quality == 2:
+            options.quality = 1
+    # 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!")
+        sys.exit(1)
+    # CBZ files on Kindle DX/DXG support higher resolution
+    if options.profile == 'KDX' and options.cbzoutput:
+        options.customheight = 1200
+    # Override profile data
+    if options.customwidth != 0 or options.customheight != 0:
+        X = image.ProfileData.Profiles[options.profile][1][0]
+        Y = image.ProfileData.Profiles[options.profile][1][1]
+        if options.customwidth != 0:
+            X = options.customwidth
+        if options.customheight != 0:
+            Y = options.customheight
+        newProfile = ("Custom", (X, Y), image.ProfileData.Palette16, image.ProfileData.Profiles[options.profile][3],
+                      (int(X*1.5), int(Y*1.5)))
+        image.ProfileData.Profiles["Custom"] = newProfile
+        options.profile = "Custom"
+    options.profileData = image.ProfileData.Profiles[options.profile]
 
 
 def makeBook(source, qtGUI=None):
     """Generates EPUB/CBZ comic ebook from a bunch of images."""
     global GUI
     GUI = qtGUI
+    if GUI:
+        GUI.progressBarTick.emit('1')
     path = getWorkFolder(source)
     print("\nChecking images...")
     detectCorruption(os.path.join(path, "OEBPS", "Images"), source)
-    checkComicInfo(os.path.join(path, "OEBPS", "Images"), source)
-
+    getComicInfo(os.path.join(path, "OEBPS", "Images"), source)
     if options.webtoon:
         if options.customheight > 0:
             comic2panel.main(['-y ' + str(options.customheight), '-i', '-m', path], qtGUI)
         else:
             comic2panel.main(['-y ' + str(image.ProfileData.Profiles[options.profile][1][1]), '-i', '-m', path], qtGUI)
-
     if options.imgproc:
         print("\nProcessing images...")
         if GUI:
             GUI.progressBarTick.emit('Processing images')
-        dirImgProcess(os.path.join(path, "OEBPS", "Images"))
-
+        imgDirectoryProcessing(os.path.join(path, "OEBPS", "Images"))
     if GUI:
         GUI.progressBarTick.emit('1')
-
     chapterNames = sanitizeTree(os.path.join(path, 'OEBPS', 'Images'))
-
     if options.batchsplit:
-        tomes = preSplitDirectory(path)
+        tomes = splitDirectory(path)
     else:
         tomes = [path]
-
     filepath = []
     tomeNumber = 0
-
     if GUI:
         if options.cbzoutput:
             GUI.progressBarTick.emit('Compressing CBZ files')
@@ -1011,14 +1066,11 @@ def makeBook(source, qtGUI=None):
             GUI.progressBarTick.emit('Compressing EPUB files')
         GUI.progressBarTick.emit(str(len(tomes) + 1))
         GUI.progressBarTick.emit('tick')
-
     options.baseTitle = options.title
-
     for tome in tomes:
         if len(tomes) > 1:
             tomeNumber += 1
             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...")
@@ -1029,97 +1081,15 @@ def makeBook(source, qtGUI=None):
             makeZIP(tome + '_comic', os.path.join(tome, "OEBPS", "Images"))
         else:
             print("\nCreating EPUB structure...")
-            genEpubStruct(tome, chapterNames)
+            buildEPUB(tome, chapterNames)
             # actually zip the ePub
             if len(tomes) > 1:
                 filepath.append(getOutputFilename(source, options.output, '.epub', ' ' + str(tomeNumber)))
             else:
                 filepath.append(getOutputFilename(source, options.output, '.epub', ''))
             makeZIP(tome + '_comic', tome, True)
-
         move(tome + '_comic.zip', filepath[-1])
         rmtree(tome, True)
-
         if GUI:
             GUI.progressBarTick.emit('tick')
-    return filepath
-
-
-def getOutputFilename(srcpath, wantedname, ext, tomeNumber):
-    if srcpath[-1] == os.path.sep:
-        srcpath = srcpath[:-1]
-    if not ext.startswith('.'):
-        ext = '.' + ext
-    if wantedname is not None:
-        if wantedname.endswith(ext):
-            filename = os.path.abspath(wantedname)
-        elif os.path.isdir(srcpath):
-            filename = os.path.join(os.path.abspath(options.output), os.path.basename(srcpath) + ext)
-        else:
-            filename = os.path.join(os.path.abspath(options.output),
-                                    os.path.basename(os.path.splitext(srcpath)[0]) + ext)
-    elif os.path.isdir(srcpath):
-        filename = srcpath + tomeNumber + ext
-    else:
-        filename = os.path.splitext(srcpath)[0] + tomeNumber + ext
-    if os.path.isfile(filename):
-        counter = 0
-        basename = os.path.splitext(filename)[0]
-        while os.path.isfile(basename + '_kcc' + str(counter) + ext):
-            counter += 1
-        filename = basename + '_kcc' + str(counter) + ext
-    return filename
-
-
-def checkOptions():
-    global options
-    options.panelview = True
-    options.bordersColor = None
-    if options.white_borders:
-        options.bordersColor = "white"
-    if options.black_borders:
-        options.bordersColor = "black"
-    # Disabling grayscale conversion for Kindle Fire family.
-    if options.profile == 'KF' or options.profile == 'KFHD' or options.profile == 'KFHD8' or options.profile == 'KFHDX'\
-       or options.profile == 'KFHDX8' or options.forcecolor:
-        options.forcecolor = True
-    else:
-        options.forcecolor = False
-    # Older Kindle don't need higher resolution files due lack of Panel View.
-    if options.profile == 'K1' or options.profile == 'K2' or options.profile == 'KDX':
-        options.quality = 0
-        options.panelview = False
-    # Webtoon mode mandatory options
-    if options.webtoon:
-        options.nosplitrotate = True
-        options.quality = 0
-        options.panelview = False
-    # Disable all Kindle features for other e-readers
-    if options.profile == 'OTHER':
-        options.panelview = False
-        options.quality = 0
-    if 'Ko' in options.profile:
-        options.panelview = False
-        # Kobo models can't use ultra quality mode
-        if options.quality == 2:
-            options.quality = 1
-    # 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!")
-        sys.exit(1)
-    # CBZ files on Kindle DX/DXG support higher resolution
-    if options.profile == 'KDX' and options.cbzoutput:
-        options.customheight = 1200
-    # Override profile data
-    if options.customwidth != 0 or options.customheight != 0:
-        X = image.ProfileData.Profiles[options.profile][1][0]
-        Y = image.ProfileData.Profiles[options.profile][1][1]
-        if options.customwidth != 0:
-            X = options.customwidth
-        if options.customheight != 0:
-            Y = options.customheight
-        newProfile = ("Custom", (X, Y), image.ProfileData.Palette16, image.ProfileData.Profiles[options.profile][3],
-                      (int(X*1.5), int(Y*1.5)))
-        image.ProfileData.Profiles["Custom"] = newProfile
-        options.profile = "Custom"
-    options.profileData = image.ProfileData.Profiles[options.profile]
+    return filepath
\ No newline at end of file
diff --git a/kcc/comic2panel.py b/kcc/comic2panel.py
index 3a36777..18421f5 100644
--- a/kcc/comic2panel.py
+++ b/kcc/comic2panel.py
@@ -36,7 +36,7 @@ except ImportError:
     QtCore = None
 
 
-def mergeDirectory_tick(output):
+def mergeDirectoryTick(output):
     if output:
         mergeWorkerOutput.append(output)
         mergeWorkerPool.terminate()
@@ -108,7 +108,7 @@ def sanitizePanelSize(panel, opt):
     return newPanels
 
 
-def splitImage_tick(output):
+def splitImageTick(output):
     if output:
         splitWorkerOutput.append(output)
         splitWorkerPool.terminate()
@@ -207,10 +207,6 @@ def splitImage(work):
         return str(sys.exc_info()[1])
 
 
-def Copyright():
-    print(('comic2panel v%(__version__)s. Written by Ciro Mattia Gonano and Pawel Jastrzebski.' % globals()))
-
-
 def main(argv=None, qtGUI=None):
     global options, GUI, splitWorkerPool, splitWorkerOutput, mergeWorkerPool, mergeWorkerOutput
     parser = OptionParser(usage="Usage: kcc-c2p [options] comic_folder", add_help_option=False)
@@ -261,7 +257,7 @@ def main(argv=None, qtGUI=None):
                     GUI.progressBarTick.emit('Combining images')
                     GUI.progressBarTick.emit(str(directoryNumer))
                 for i in mergeWork:
-                    mergeWorkerPool.apply_async(func=mergeDirectory, args=(i, ), callback=mergeDirectory_tick)
+                    mergeWorkerPool.apply_async(func=mergeDirectory, args=(i, ), callback=mergeDirectoryTick)
                 mergeWorkerPool.close()
                 mergeWorkerPool.join()
                 if GUI and not GUI.conversionAlive:
@@ -284,7 +280,7 @@ def main(argv=None, qtGUI=None):
                 GUI.progressBarTick.emit('tick')
             if len(work) > 0:
                 for i in work:
-                    splitWorkerPool.apply_async(func=splitImage, args=(i, ), callback=splitImage_tick)
+                    splitWorkerPool.apply_async(func=splitImage, args=(i, ), callback=splitImageTick)
                 splitWorkerPool.close()
                 splitWorkerPool.join()
                 if GUI and not GUI.conversionAlive: