Skip to content

Commit

Permalink
Merge branch 'dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
Haoyi-Han committed Jan 14, 2024
2 parents ad9a0be + 01ba918 commit de94ffd
Show file tree
Hide file tree
Showing 8 changed files with 322 additions and 97 deletions.
2 changes: 1 addition & 1 deletion .version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.1.13
0.1.14
145 changes: 118 additions & 27 deletions main.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
# 主程序引用库
import os
import pathlib
from pathlib import Path
from contextlib import AbstractContextManager
from types import TracebackType
from argparse import ArgumentParser, Namespace, RawTextHelpFormatter

# 程序显示引用库
from rich.prompt import Prompt

# 程序异常打印库
from rich.traceback import install

from rich.progress import Progress, TaskID

import moe_utils.file_system as mfst
import moe_utils.manga_repacker as mmrp
import moe_utils.progress_bar as mpbr
Expand All @@ -23,7 +29,48 @@
repacker = mmrp.Repacker(console=console)

# 全局初始化 Windows 任务栏对象 20230521
win_tb = mtbi.WinTaskbar()
win_tb: mtbi.WinTaskbar | None = None


# 使用上下文管理器进行封装 20231228
class ProgressController(AbstractContextManager):
pb: Progress
tb: mtbi.WinTaskbar | None = None
tb_imported: bool = False
description: str
total: int
task: TaskID

def __init__(
self, pb: Progress, tb: mtbi.WinTaskbar | None, description: str, total: int
):
super().__init__()
self.pb = pb
self.tb = tb
self.tb_imported = isinstance(tb, mtbi.WinTaskbar)
self.description = description
self.total = total

def __enter__(self):
self.pb.start()
self.task = self.pb.add_task(description=self.description, total=self.total)
return super().__enter__()

def __exit__(
self,
__exc_type: type[BaseException] | None,
__exc_value: BaseException | None,
__traceback: TracebackType | None,
) -> bool | None:
self.pb.stop()
if self.tb_imported:
self.tb.reset_taskbar_progress()
return super().__exit__(__exc_type, __exc_value, __traceback)

def update(self, i: int):
self.pb.update(self.task, advance=1)
if self.tb_imported:
self.tb.set_taskbar_progress(i, self.total)


# 键盘Ctrl+C中断命令优化
Expand All @@ -32,18 +79,23 @@ def keyboard_handler(signum, frame):
# 重置进度条
global repacker, console, win_tb, pb
pb.stop()
win_tb.reset_taskbar_progress()
if win_tb is not None:
win_tb.reset_taskbar_progress()

# 选择是否保留已转换文件和缓存文件夹
console.print('[yellow]您手动中断了程序。')
resp_out = Prompt.ask("请选择是否保留已转换文件", choices=["y", "n"], default="y")
resp_cache = Prompt.ask("请选择是否保留缓存文件夹", choices=["y", "n"], default="n")
console.print("[yellow]您手动中断了程序。")
resp_out = Prompt.ask(
"请选择是否保留已转换文件", choices=["y", "n"], default="y"
)
resp_cache = Prompt.ask(
"请选择是否保留缓存文件夹", choices=["y", "n"], default="n"
)
# 除打包阶段使用的当前电子书文件外,其他文件均可清除
# 之后会考虑将打包阶段作为独立进程,并在中断退出时结束
if resp_out == 'n':
if resp_out == "n":
os.chdir(repacker.input_dir) # 防止进程占用输出文件夹 20230429
mfst.remove_if_exists(repacker.output_dir)
if resp_cache != 'y':
if resp_cache != "y":
os.chdir(repacker.input_dir) # 防止进程占用缓存文件夹 20230429
mfst.remove_if_exists(repacker.cache_dir)
finally:
Expand All @@ -52,47 +104,86 @@ def keyboard_handler(signum, frame):

# 将主要执行过程封装,用于单线程或多线程时调用 20230429
# 将执行过程提取到主函数外部 20230521
def work(file_t):
repacker.repack(pathlib.Path(file_t))
def work(file_t: Path):
repacker.repack(file_t)


# 主程序
def main():
# 优化键盘中断命令
import signal

signal.signal(signal.SIGINT, keyboard_handler)
signal.signal(signal.SIGTERM, keyboard_handler)

# 命令行参数列表 20231230
parser = ArgumentParser(
description=mtui.welcome_logo, formatter_class=RawTextHelpFormatter
)
parser.add_argument(
"-if", "--input-dir", type=str, default=None, help="Input Directory Path"
)
parser.add_argument(
"-of", "--output-dir", type=str, default=None, help="Output Directory Path"
)
parser.add_argument(
"-cc", "--cache-dir", type=str, default=None, help="Cache Directory Path"
)
parser.add_argument(
"-cl", "--clean-all", action="store_true", help="Clean Output and Cache files"
)
parser.add_argument(
"-nt",
"--no-taskbar",
action="store_true",
help="Disable Taskbar Progress Display",
)
parser.add_argument("-nl", "--no-logo", action="store_true", help="Disable Logo")
args: Namespace = parser.parse_args()

# 欢迎界面
console.print(mtui.welcome_panel)
if not args.no_logo:
console.print(mtui.welcome_panel)

# 初始化转换器对象
repacker.init_from_config('./config.toml')
repacker.init_data(config_path="./config.toml", args=args)

# 若存在参数 cl,则运行清理命令并退出 20231230
if args.clean_all:
mtui.log(console, "[yellow]开始清理输出文件...")
mfst.remove_if_exists(repacker.output_dir)
os.mkdir(repacker.output_dir)
mtui.log(console, "[yellow]开始清理缓存文件...")
mfst.remove_if_exists(repacker.cache_dir)
return

# 若存在参数 nt,则不加载任务栏进度条
win_tb = None
if not args.no_taskbar:
win_tb = mtbi.create_wintaskbar_object()

# 采用 rich.progress 实现进度条效果
mtui.log(console, '[yellow]开始提取图片并打包文件...')
pb.start()
total = len(repacker.filelist)
task = pb.add_task(description='Kox.moe', total=total)
mtui.log(console, "[yellow]开始提取图片并打包文件...")

# 引入 CPU 线程池,提高任务执行效率 20230429
# 更改 CPU 线程池为 CPU 进程池 20230521
# 弃用多进程/多线程,改用异步 20230525
# 移除所有多进程/多线程/协程模块 20230528
for i, file_t in enumerate(repacker.filelist):
work(file_t)
win_tb.set_taskbar_progress(i, total)
pb.update(task, advance=1)

pb.stop()
win_tb.reset_taskbar_progress()

mtui.log(console, '[yellow]开始清理缓存文件...')
# 使用上下文管理器进行封装 20231228
with ProgressController(
pb=pb, tb=win_tb, description="Kox.moe", total=len(repacker.filelist)
) as pctrl:
pctrl: ProgressController
for i, file_t in enumerate(repacker.filelist):
work(file_t)
pctrl.update(i)

mtui.log(console, "[yellow]开始清理缓存文件...")
os.chdir(repacker.output_dir) # 防止进程占用缓存文件夹 20230429
mfst.remove_if_exists(repacker.cache_dir)

mtui.log(console, '[green]所有转换任务完成!')
mtui.log(console, "[green]所有转换任务完成!")


if __name__ == '__main__':
if __name__ == "__main__":
main()
32 changes: 16 additions & 16 deletions moe_utils/comic_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,11 +175,17 @@ def __init__(self, opf_file: Path):
self._build_mox_book()
self._build_comic_info()

# 安全搜索,避免返回空列表引发错误
def _get_xpath_text(self, xpath: str) -> str:
res: str = ""
res_finder = self._package.xpath(xpath, namespaces=self.ns)
if res_finder:
res = res_finder[0].text
return res

def _build_mox_book(self):
moxbid = self._package.xpath(
'.//dc:identifier[@id="MOXBID"]', namespaces=self.ns
)[0].text
title = self._package.xpath(".//dc:title", namespaces=self.ns)[0].text
moxbid: str = self._get_xpath_text('.//dc:identifier[@id="MOXBID"]')
title: str = self._get_xpath_text(".//dc:title")
volume = title.split(" - ")[-1].strip()
self._mox_book = MoxBook(moxbid, volume)
self._comic_data["MOXBID"] = moxbid
Expand All @@ -190,18 +196,12 @@ def _build_mox_book(self):
self._comic_data["Web"] = self.mox_book.weburl

def _build_comic_info(self):
self._comic_data["Series"] = self._package.xpath(
".//dc:series", namespaces=self.ns
)[0].text
self._comic_data["Writer"] = self._package.xpath(
".//dc:creator", namespaces=self.ns
)[0].text
self._comic_data["Publisher"] = self._package.xpath(
".//dc:publisher", namespaces=self.ns
)[0].text
self._comic_data["Year"] = self._package.xpath(
".//dc:date", namespaces=self.ns
)[0].text
self._comic_data["Series"] = self._get_xpath_text(".//dc:series")
self._comic_data["Writer"] = self._get_xpath_text(".//dc:creator")
self._comic_data["Publisher"] = self._get_xpath_text(
".//dc:publisher"
)
self._comic_data["Year"] = self._get_xpath_text(".//dc:date")
self._comic_data["PageCount"] = len(
self._package.xpath(
'.//opf:spine[@toc="ncx"]/opf:itemref[@idref]', namespaces=self.ns
Expand Down
66 changes: 51 additions & 15 deletions moe_utils/file_system.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import zipfile
from pathlib import Path

from rich.prompt import Prompt


# 在指定目录下复制空目录结构
# 使用 shutil.ignore_patterns() 代替自定义排除函数 20230429
Expand All @@ -20,30 +22,24 @@ def copy_dir_struct(inPath: str, outPath: str, exclude=None):


# 创建文件列表(按原目录结构)
def copy_dir_struct_to_list(root: str) -> list:
# return [pathlib.Path(os.path.join(path, name)) for path, subdirs, files in os.walk(root) for name in files]
def copy_dir_struct_to_list(root: str) -> list[Path]:
return [
os.path.join(path, name)
for path, subdirs, files in os.walk(root)
for name in files
Path(path, name) for path, subdirs, files in os.walk(root) for name in files
]


# 创建EPUB文件列表(按原目录结构)
def copy_dir_struct_ext_to_list(root: str, ext=".epub") -> list:
filelist: list = copy_dir_struct_to_list(root)
return [
p
for p in filelist
if (not Path(p).stem.startswith("._")) and (Path(p).suffix == ext)
]
def copy_dir_struct_ext_to_list(root: str, ext=".epub") -> list[Path]:
filelist: list[Path] = copy_dir_struct_to_list(root)
return [p for p in filelist if (not p.stem.startswith("._")) and (p.suffix == ext)]


# 修改EPUB扩展名为ZIP
# 调整shutil.unpack_archive()参数后,解压不再需要依赖扩展名,本函数弃用
def suffix_change(filelist: list, inType: str = ".epub", outType: str = ".zip") -> list:
for i in range(len(filelist)):
filepath = filelist[i]
def suffix_change(
filelist: list[Path], inType: str = ".epub", outType: str = ".zip"
) -> list:
for i, filepath in enumerate(filelist):
if filepath.suffix == inType:
filepath = filepath.rename(filepath.with_suffix(outType))
filelist[i] = filepath
Expand All @@ -65,3 +61,43 @@ def make_archive_threadsafe(zip_name: str, path: str):
os.path.join(root, file),
os.path.relpath(os.path.join(root, file), path),
)


# 检查字符串是否能够组成路径
def check_if_path_string_valid(
path_string: str, check_only: bool = True, force_create: bool = False
) -> Path | None:
try:
if path_string is None:
return None
path = Path(path_string)
if not path.exists():
if check_only:
print(f"警告:{path_string} 路径指向的文件夹不存在。")
return None

if not force_create:
create_folder = Prompt.ask(
f"警告:{path_string} 路径指向的文件夹不存在,您想要创建吗?",
choices=["y", "n"],
default="n",
)
if create_folder == "y":
path.mkdir(parents=True, exist_ok=True)
return path
else:
return None

path.mkdir(parents=True, exist_ok=True)
return path
elif path.is_file():
print("警告:该路径指向一个已存在的文件。")
return None
elif not os.access(path, os.R_OK):
print("警告:该路径指向一个已存在的文件夹,但访问受限或被拒绝。")
return None
else:
return path
except Exception as e:
print(f"警告:{e}")
return None
Loading

0 comments on commit de94ffd

Please sign in to comment.