From 978f13ebed3d548b5ef289ef2081d5502d78e2d4 Mon Sep 17 00:00:00 2001 From: sakamoto Date: Fri, 9 Aug 2024 13:45:59 -0500 Subject: [PATCH] =?UTF-8?q?=F0=9F=A7=B1=20massive=20revamp?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- comic2pdf.py | 202 ++++++++++++++++++++------------------------------- utils.py | 34 +++++++++ 2 files changed, 114 insertions(+), 122 deletions(-) create mode 100644 utils.py diff --git a/comic2pdf.py b/comic2pdf.py index b174c91..5f2762f 100755 --- a/comic2pdf.py +++ b/comic2pdf.py @@ -1,140 +1,98 @@ -# Created on iPad. -# Comic to PDF Converter +from utils import Sorter +from utils import src, dest, verbose +from utils import log -# version 1.0 +import os +import img2pdf +import tempfile +import patoolib +import shutil -import os, re, argparse, tqdm, img2pdf, pathlib, tempfile, patoolib -from tqdm import tqdm -from send2trash import send2trash - -parser = argparse.ArgumentParser( - description="Converts comic book zipfiles to PDF.", - formatter_class=argparse.ArgumentDefaultsHelpFormatter, -) -parser.add_argument("-src", help="location of file(s) to convert") -parser.add_argument("-dest", help="destination of converted files") -parser.add_argument( - "-t", - "--trash-old", - action="store_true", - help="places converted cbz and cbr to the trash", -) -parser.add_argument( - "-d", - "--delete-old", - action="store_true", - help="delete cbz and cbr that are converted", -) - -args = parser.parse_args() - -src = args.src -dest = args.dest -delete_old = args.delete_old -trash_old = args.trash_old - -print(f"The source file is: {args.source}") -print(f"The destination file is: {args.dest}") class Comic2PDF: - def __init__(self, src, dest): - # huh? this needs to be fixed. I can't read it - # horrible use of OOP - src = self.check_src(src, dest) - dest = self.check_dest(src, dest) + def __init__(self, src, dest, verbose=False, use_tempfile=False): + self.sort = Sorter() + + self.src = src + self.dest = dest + self.dest_temp_dir = os.path.join(dest, "tmp") + self.define_temp = ( + tempfile.TemporaryDirectory() if use_tempfile else self.dest_temp_dir + ) + self.temp_dir = ( + self.define_temp.name + if isinstance(self.define_temp, tempfile.TemporaryDirectory) + else self.define_temp + ) + + os.makedirs(self.dest, exist_ok=True) + os.makedirs(self.dest_temp_dir, exist_ok=True) + os.makedirs(self.temp_dir, exist_ok=True) + + log.info(f"Source: {self.src}") + log.info(f"Destination: {self.dest}") + log.debug(f"Temp Dir: {self.temp_dir}") + log.debug(f"Dest Temp Dir: {self.dest_temp_dir}") + + def __del__(self): + delete_it = True + try: + if delete_it: + log.debug(f"Deleting: {self.dest_temp_dir}") + shutil.rmtree(self.dest_temp_dir) + except Exception as e: + log.error(e) + + def run(self): + if os.path.isfile(self.src): + self.extract(self.src) + self.convert(self.src) - if src.endswith(".cbz") or src.endswith(".cbr"): - self.convert_single_file(src, dest) else: - self.batch_convert(src, dest) + scanned_folder = self.scan(self.src) + log.debug(f"scanned folder: {scanned_folder}") + for root, dirs, files in os.walk(self.src): + for file in files: + log.info("="*30) + self.__del__() + os.makedirs(self.temp_dir) + self.extract(file) + self.convert(file) - def check_src(self, src, dest): - if (src is None and dest is None) or (src is None and dest is not None): - # src = os.path.realpath(__file__) - src = os.getcwd() - src = os.path.dirname(src) - return src - else: - return src + def scan(self, dir): + log.info(f"Scanning {dir}") - def check_dest(self, src, dest): - if dest is None and src is None: - # dest = os.path.realpath(__file__) - dest = os.getcwd() - dest = os.path.dirname(dest) - return dest - elif dest is None and src is not None: - if src.endswith(".cbz") or src.endswith(".cbr"): - dest = pathlib.Path(src).parents[0] - else: - dest = pathlib.Path(src) - return dest - else: - return dest + files_in_folder = [] - def scan_folder(self, src): - filesIn_folder = [] - - for root, dirs, files in os.walk(src): + for root, dirs, files in os.walk(dir): for name in files: if name.endswith((".png", ".jpg", ".jpeg", ".cbz", ".cbr")): - filesIn_folder.append(os.path.join(root, name)) + files_in_folder.append(os.path.join(root, name)) - filesIn_folder.sort(key=natural_keys) - return filesIn_folder + files_in_folder.sort(key=self.sort.natural_keys) + log.info(f"Found {len(files_in_folder)} files.") + return files_in_folder - def convert_to_pdf(self, src, dest, name): + def extract(self, file): + log.info(f"Extracting... {file}") + + path_file = os.path.join(self.src, file) + patoolib.extract_archive(path_file, outdir=self.temp_dir, verbosity=-1) + + log.info("Extraction Complete") + + def convert(self, file): + log.info("Converting to pdf...") imgs = [] - imgs = self.scan_folder(src) - pdf_path = f"{dest}/{name}.pdf" + imgs = self.scan(self.temp_dir) + basename = os.path.basename(file) + name = os.path.splitext(basename)[0] + pdf_path = os.path.join(self.dest, f"{name}.pdf") with open(pdf_path, "wb") as f: f.write(img2pdf.convert(imgs)) - def convert_single_file(self, src, dest): - with tempfile.TemporaryDirectory() as temp_dict: - folder_parents = pathlib.Path(temp_dict) - name = pathlib.Path(src).stem - patoolib.extract_archive(src, outdir=temp_dict) - list_folderInside = next(os.walk(folder_parents))[1] + log.info("Conversion complete") - try: - storage = f"{temp_dict}/{list_folderInside[0]}" - except: - storage = f"{temp_dict}/" - - self.convert_to_pdf(src=storage, dest=dest, name=name) - - if trash_old is True: - send2trash(f"{src}") - - if delete_old is True: - os.remove(f"{src}") - - def batch_convert(self, src, dest): - for root, dir, files in os.walk(src): - pstat = [f for f in files if f.endswith(".cbr") or f.endswith(".cbz")] - pbar = tqdm(total=len(pstat)) - queue = 0 - - for name in files: - if name.endswith(".cbz") or name.endswith(".cbr"): - pbar.set_description(f"Converting {name}") - self.convert_single_file(os.path.join(root, name), dest) - pbar.update(1) - queue += 1 - else: - pass - break - - -# exported from the internet; -# sorts folder name to human order -def atoi(text): - return int(text) if text.isdigit() else text - - -def natural_keys(text): - return [atoi(c) for c in re.split(r"(d )", text)] - - -Comic2PDF(src, dest) +if __name__ == "__main__": + comic2pdf = Comic2PDF(src, dest, verbose) + comic2pdf.run() diff --git a/utils.py b/utils.py new file mode 100644 index 0000000..216071f --- /dev/null +++ b/utils.py @@ -0,0 +1,34 @@ +import re +import argparse +import logging + +parser = argparse.ArgumentParser( + description="A comic archive to pdf converter.", + formatter_class=argparse.ArgumentDefaultsHelpFormatter, +) + +parser.add_argument("source", type=str, help="source of file/folder with .cbz or .cbr format") +parser.add_argument( + "destination", type=str, help="ouptput of the converted files" +) +parser.add_argument("-v", "--verbose", action="store_true", help="debug mode") + +args = parser.parse_args() +src = args.source +dest = args.destination +verbose = args.verbose + +if verbose: + logging.basicConfig(level=logging.DEBUG, format="[%(levelname)s] - %(message)s") +else: + logging.basicConfig(level=logging.INFO, format="[%(levelname)s] - %(message)s") +log = logging.getLogger() + +# got this from the internet +class Sorter: + def atoi(self, text): + return int(text) if text.isdigit() else text + + def natural_keys(self, text): + return [self.atoi(c) for c in re.split(r"(d )", text)] +