mirror of
https://github.com/ciromattia/kcc
synced 2026-06-11 17:10:34 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 21249854b9 |
@@ -40,10 +40,10 @@ from packaging.version import Version
|
|||||||
from raven import Client
|
from raven import Client
|
||||||
from tempfile import gettempdir
|
from tempfile import gettempdir
|
||||||
|
|
||||||
from .shared import HTMLStripper, sanitizeTrace, walkLevel, subprocess_run
|
from .shared import HTMLStripper, available_archive_tools, sanitizeTrace, walkLevel, subprocess_run
|
||||||
from .comicarchive import SEVENZIP, available_archive_tools
|
|
||||||
from . import __version__
|
from . import __version__
|
||||||
from . import comic2ebook
|
from . import comic2ebook
|
||||||
|
from . import image
|
||||||
from . import metadata
|
from . import metadata
|
||||||
from . import kindle
|
from . import kindle
|
||||||
from . import KCC_ui
|
from . import KCC_ui
|
||||||
@@ -1166,7 +1166,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
'info')
|
'info')
|
||||||
|
|
||||||
self.tar = 'tar' in available_archive_tools()
|
self.tar = 'tar' in available_archive_tools()
|
||||||
self.sevenzip = SEVENZIP in available_archive_tools()
|
self.sevenzip = '7z' in available_archive_tools()
|
||||||
if not any([self.tar, self.sevenzip]):
|
if not any([self.tar, self.sevenzip]):
|
||||||
self.addMessage('<a href="https://github.com/ciromattia/kcc#7-zip">Install 7z (link)</a>'
|
self.addMessage('<a href="https://github.com/ciromattia/kcc#7-zip">Install 7z (link)</a>'
|
||||||
' to enable CBZ/CBR/ZIP/etc processing.', 'warning')
|
' to enable CBZ/CBR/ZIP/etc processing.', 'warning')
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
__version__ = '8.0.1'
|
__version__ = '8.0.0'
|
||||||
__license__ = 'ISC'
|
__license__ = 'ISC'
|
||||||
__copyright__ = '2012-2022, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>, darodi'
|
__copyright__ = '2012-2022, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>, darodi'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ from tempfile import mkdtemp, gettempdir, TemporaryFile
|
|||||||
from shutil import move, copytree, rmtree, copyfile
|
from shutil import move, copytree, rmtree, copyfile
|
||||||
from multiprocessing import Pool
|
from multiprocessing import Pool
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
from natsort import os_sort_keygen, os_sorted
|
from natsort import os_sort_keygen
|
||||||
from slugify import slugify as slugify_ext
|
from slugify import slugify as slugify_ext
|
||||||
from PIL import Image, ImageFile
|
from PIL import Image, ImageFile
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
@@ -42,8 +42,7 @@ from subprocess import STDOUT, PIPE, CalledProcessError
|
|||||||
from psutil import virtual_memory, disk_usage
|
from psutil import virtual_memory, disk_usage
|
||||||
from html import escape as hescape
|
from html import escape as hescape
|
||||||
|
|
||||||
from .shared import getImageFileName, walkSort, walkLevel, sanitizeTrace, subprocess_run
|
from .shared import available_archive_tools, getImageFileName, walkSort, walkLevel, sanitizeTrace, subprocess_run
|
||||||
from .comicarchive import SEVENZIP, available_archive_tools
|
|
||||||
from . import comic2panel
|
from . import comic2panel
|
||||||
from . import image
|
from . import image
|
||||||
from . import comicarchive
|
from . import comicarchive
|
||||||
@@ -834,27 +833,24 @@ def sanitizeTree(filetree):
|
|||||||
page = 1
|
page = 1
|
||||||
cover_path = None
|
cover_path = None
|
||||||
for root, dirs, files in os.walk(filetree):
|
for root, dirs, files in os.walk(filetree):
|
||||||
|
dirs.sort(key=OS_SORT_KEY)
|
||||||
files.sort(key=OS_SORT_KEY)
|
files.sort(key=OS_SORT_KEY)
|
||||||
for name in files:
|
for name in files:
|
||||||
_, ext = getImageFileName(name)
|
_, ext = getImageFileName(name)
|
||||||
|
|
||||||
# 9999 page limit
|
# 9999 page limit
|
||||||
unique_name = f'kcc-{page:04}'
|
slugified = f'kcc-{page:04}'
|
||||||
page += 1
|
page += 1
|
||||||
|
|
||||||
newKey = os.path.join(root, unique_name + ext)
|
newKey = os.path.join(root, slugified + ext)
|
||||||
key = os.path.join(root, name)
|
key = os.path.join(root, name)
|
||||||
if key != newKey:
|
if key != newKey:
|
||||||
os.replace(key, newKey)
|
os.replace(key, newKey)
|
||||||
if not cover_path:
|
if not cover_path:
|
||||||
cover_path = newKey
|
cover_path = newKey
|
||||||
is_natural_sorted = False
|
|
||||||
if os_sorted(dirs) == sorted(dirs):
|
|
||||||
is_natural_sorted = True
|
|
||||||
dirs.sort(key=OS_SORT_KEY)
|
|
||||||
for i, name in enumerate(dirs):
|
for i, name in enumerate(dirs):
|
||||||
tmpName = name
|
tmpName = name
|
||||||
slugified = slugify(name, is_natural_sorted)
|
slugified = slugify(name)
|
||||||
while os.path.exists(os.path.join(root, slugified)) and name.upper() != slugified.upper():
|
while os.path.exists(os.path.join(root, slugified)) and name.upper() != slugified.upper():
|
||||||
slugified += "A"
|
slugified += "A"
|
||||||
chapterNames[slugified] = tmpName
|
chapterNames[slugified] = tmpName
|
||||||
@@ -1021,27 +1017,23 @@ def createNewTome(parent):
|
|||||||
return tomePath, tomePathRoot
|
return tomePath, tomePathRoot
|
||||||
|
|
||||||
|
|
||||||
def slugify(value, is_natural_sorted):
|
def slugify(value):
|
||||||
if options.format == 'CBZ' and is_natural_sorted:
|
if options.format == 'CBZ':
|
||||||
return value
|
return value
|
||||||
if options.format != 'CBZ':
|
value = slugify_ext(value, regex_pattern=r'[^-a-z0-9_\.]+').strip('.')
|
||||||
# convert all unicode to ascii via slugify
|
value = sub(r'0*([0-9]{4,})', r'\1', sub(r'([0-9]+)', r'0000\1', value, count=2))
|
||||||
value = slugify_ext(value, regex_pattern=r'[^-a-z0-9_\.]+').strip('.')
|
|
||||||
if not is_natural_sorted:
|
|
||||||
# pad zeros to numbers
|
|
||||||
value = sub(r'0*([0-9]{4,})', r'\1', sub(r'([0-9]+)', r'0000\1', value, count=2))
|
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
def makeZIP(zipfilename, basedir, isepub=False):
|
def makeZIP(zipfilename, basedir, isepub=False):
|
||||||
start = perf_counter()
|
start = perf_counter()
|
||||||
zipfilename = os.path.abspath(zipfilename) + '.zip'
|
zipfilename = os.path.abspath(zipfilename) + '.zip'
|
||||||
if SEVENZIP in available_archive_tools():
|
if '7z' in available_archive_tools():
|
||||||
if isepub:
|
if isepub:
|
||||||
mimetypeFile = open(os.path.join(basedir, 'mimetype'), 'w')
|
mimetypeFile = open(os.path.join(basedir, 'mimetype'), 'w')
|
||||||
mimetypeFile.write('application/epub+zip')
|
mimetypeFile.write('application/epub+zip')
|
||||||
mimetypeFile.close()
|
mimetypeFile.close()
|
||||||
subprocess_run([SEVENZIP, 'a', '-tzip', zipfilename, os.path.join(basedir, "*")], capture_output=True, check=True)
|
subprocess_run(['7z', 'a', '-tzip', zipfilename, os.path.join(basedir, "*")], capture_output=True, check=True)
|
||||||
else:
|
else:
|
||||||
zipOutput = ZipFile(zipfilename, 'w', ZIP_DEFLATED)
|
zipOutput = ZipFile(zipfilename, 'w', ZIP_DEFLATED)
|
||||||
if isepub:
|
if isepub:
|
||||||
@@ -1241,7 +1233,7 @@ def checkTools(source):
|
|||||||
source = source.upper()
|
source = source.upper()
|
||||||
if source.endswith('.CB7') or source.endswith('.7Z') or source.endswith('.RAR') or source.endswith('.CBR') or \
|
if source.endswith('.CB7') or source.endswith('.7Z') or source.endswith('.RAR') or source.endswith('.CBR') or \
|
||||||
source.endswith('.ZIP') or source.endswith('.CBZ'):
|
source.endswith('.ZIP') or source.endswith('.CBZ'):
|
||||||
if SEVENZIP not in available_archive_tools():
|
if '7z' not in available_archive_tools():
|
||||||
print('ERROR: 7z is missing!')
|
print('ERROR: 7z is missing!')
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
if options.format == 'MOBI':
|
if options.format == 'MOBI':
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
# PERFORMANCE OF THIS SOFTWARE.
|
# PERFORMANCE OF THIS SOFTWARE.
|
||||||
#
|
#
|
||||||
|
|
||||||
from functools import cached_property, lru_cache
|
from functools import cached_property
|
||||||
import os
|
import os
|
||||||
import platform
|
import platform
|
||||||
import distro
|
import distro
|
||||||
@@ -28,7 +28,6 @@ from xml.parsers.expat import ExpatError
|
|||||||
from .shared import subprocess_run
|
from .shared import subprocess_run
|
||||||
|
|
||||||
EXTRACTION_ERROR = 'Failed to extract archive. Try extracting file outside of KCC.'
|
EXTRACTION_ERROR = 'Failed to extract archive. Try extracting file outside of KCC.'
|
||||||
SEVENZIP = '7zz' if platform.system() == 'Darwin' else '7z'
|
|
||||||
|
|
||||||
|
|
||||||
class ComicArchive:
|
class ComicArchive:
|
||||||
@@ -40,7 +39,7 @@ class ComicArchive:
|
|||||||
@cached_property
|
@cached_property
|
||||||
def type(self):
|
def type(self):
|
||||||
extraction_commands = [
|
extraction_commands = [
|
||||||
[SEVENZIP, 'l', '-y', '-p1', self.filepath],
|
['7z', 'l', '-y', '-p1', self.filepath],
|
||||||
]
|
]
|
||||||
|
|
||||||
if distro.id() == 'fedora' or distro.like() == 'fedora':
|
if distro.id() == 'fedora' or distro.like() == 'fedora':
|
||||||
@@ -69,7 +68,7 @@ class ComicArchive:
|
|||||||
|
|
||||||
extraction_commands = [
|
extraction_commands = [
|
||||||
['tar', '--exclude', '__MACOSX', '--exclude', '.DS_Store', '--exclude', 'thumbs.db', '--exclude', 'Thumbs.db', '-xf', self.filepath, '-C', targetdir],
|
['tar', '--exclude', '__MACOSX', '--exclude', '.DS_Store', '--exclude', 'thumbs.db', '--exclude', 'Thumbs.db', '-xf', self.filepath, '-C', targetdir],
|
||||||
[SEVENZIP, 'x', '-y', '-xr!__MACOSX', '-xr!.DS_Store', '-xr!thumbs.db', '-xr!Thumbs.db', '-o' + targetdir, self.filepath],
|
['7z', 'x', '-y', '-xr!__MACOSX', '-xr!.DS_Store', '-xr!thumbs.db', '-xr!Thumbs.db', '-o' + targetdir, self.filepath],
|
||||||
]
|
]
|
||||||
|
|
||||||
if platform.system() == 'Darwin':
|
if platform.system() == 'Darwin':
|
||||||
@@ -101,13 +100,13 @@ class ComicArchive:
|
|||||||
def addFile(self, sourcefile):
|
def addFile(self, sourcefile):
|
||||||
if self.type in ['RAR', 'RAR5']:
|
if self.type in ['RAR', 'RAR5']:
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
process = subprocess_run([SEVENZIP, 'a', '-y', self.filepath, sourcefile],
|
process = subprocess_run(['7z', 'a', '-y', self.filepath, sourcefile],
|
||||||
stdout=PIPE, stderr=STDOUT)
|
stdout=PIPE, stderr=STDOUT)
|
||||||
if process.returncode != 0:
|
if process.returncode != 0:
|
||||||
raise OSError('Failed to add the file.')
|
raise OSError('Failed to add the file.')
|
||||||
|
|
||||||
def extractMetadata(self):
|
def extractMetadata(self):
|
||||||
process = subprocess_run([SEVENZIP, 'x', '-y', '-so', self.filepath, 'ComicInfo.xml'],
|
process = subprocess_run(['7z', 'x', '-y', '-so', self.filepath, 'ComicInfo.xml'],
|
||||||
stdout=PIPE, stderr=STDOUT)
|
stdout=PIPE, stderr=STDOUT)
|
||||||
if process.returncode != 0:
|
if process.returncode != 0:
|
||||||
raise OSError(EXTRACTION_ERROR)
|
raise OSError(EXTRACTION_ERROR)
|
||||||
@@ -115,16 +114,3 @@ class ComicArchive:
|
|||||||
return parseString(process.stdout)
|
return parseString(process.stdout)
|
||||||
except ExpatError:
|
except ExpatError:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@lru_cache
|
|
||||||
def available_archive_tools():
|
|
||||||
available = []
|
|
||||||
|
|
||||||
for tool in ['tar', SEVENZIP, 'unar', 'unrar']:
|
|
||||||
try:
|
|
||||||
subprocess_run([tool], stdout=PIPE, stderr=STDOUT)
|
|
||||||
available.append(tool)
|
|
||||||
except (FileNotFoundError, CalledProcessError):
|
|
||||||
pass
|
|
||||||
|
|
||||||
return available
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
# PERFORMANCE OF THIS SOFTWARE.
|
# PERFORMANCE OF THIS SOFTWARE.
|
||||||
#
|
#
|
||||||
|
|
||||||
|
from functools import lru_cache
|
||||||
import os
|
import os
|
||||||
from html.parser import HTMLParser
|
from html.parser import HTMLParser
|
||||||
import subprocess
|
import subprocess
|
||||||
@@ -124,6 +125,19 @@ def dependencyCheck(level):
|
|||||||
print('ERROR: ' + ', '.join(missing) + ' is not installed!')
|
print('ERROR: ' + ', '.join(missing) + ' is not installed!')
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
@lru_cache
|
||||||
|
def available_archive_tools():
|
||||||
|
available = []
|
||||||
|
|
||||||
|
for tool in ['tar', '7z', 'unar', 'unrar']:
|
||||||
|
try:
|
||||||
|
subprocess_run([tool], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||||
|
available.append(tool)
|
||||||
|
except (FileNotFoundError, subprocess.CalledProcessError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
return available
|
||||||
|
|
||||||
def subprocess_run(command, **kwargs):
|
def subprocess_run(command, **kwargs):
|
||||||
if (os.name == 'nt'):
|
if (os.name == 'nt'):
|
||||||
kwargs.setdefault('creationflags', subprocess.CREATE_NO_WINDOW)
|
kwargs.setdefault('creationflags', subprocess.CREATE_NO_WINDOW)
|
||||||
|
|||||||
Reference in New Issue
Block a user