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 Feb 29, 2024
2 parents 425e1a3 + 21cd587 commit c10d10c
Show file tree
Hide file tree
Showing 9 changed files with 125 additions and 64 deletions.
2 changes: 1 addition & 1 deletion .version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.5.0
0.5.3
11 changes: 8 additions & 3 deletions main.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
# 主程序引用库
import os
from contextlib import AbstractContextManager
from argparse import ArgumentParser, Namespace, RawTextHelpFormatter
from contextlib import AbstractContextManager

from rich.progress import Progress, TaskID

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

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

from rich.progress import Progress, TaskID

from moe_utils.file_system import remove_if_exists
from moe_utils.manga_repacker import ComicFile, IRepacker, Repacker
from moe_utils.progress_bar import generate_progress_bar
Expand Down Expand Up @@ -153,6 +153,11 @@ def _convert(self):
for i, file_t in enumerate(self.repacker.filelist):
self.work(file_t)
pctrl.update(i)
if self.repacker.faillist:
self.log("[yellow]提示:以下文件转换失败!")
indent: str = " " * 11
for file_t in self.repacker.faillist:
self.print(f"{indent}{file_t.relative_path}")

# 键盘Ctrl+C中断命令优化
def keyboard_handler(self, signum, frame):
Expand Down
2 changes: 1 addition & 1 deletion moe_utils/comic_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def _full_count_str(vol: str) -> str:

@staticmethod
def _volume_count(vol: str) -> int:
return int(vol.replace("卷", ""))
return int(re.sub(r"卷(\d+).*", r"\1", vol))

@staticmethod
def _volume_count_str(vol: str) -> str:
Expand Down
54 changes: 40 additions & 14 deletions moe_utils/file_system.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,49 @@
import shutil
import subprocess
import time
from typing import Sequence
import zipfile
from pathlib import Path
from typing import Sequence

from rich.prompt import Prompt
import filedate
from rich import print
from rich.prompt import Prompt

from .terminal_ui import pure_log

GeneralPath = str | os.PathLike | None
GeneralPathUnwrapped = str | os.PathLike


def make_path(path: GeneralPath) -> Path | None:
def make_path(path: GeneralPath, resolve: bool = False) -> Path | None:
if path is None:
return None
if isinstance(path, Path):
return path.resolve()
return path.resolve() if resolve else path
try:
path = Path(path).resolve()
return path
except Exception:
return None


def make_paths(paths: Sequence[GeneralPath]) -> list[Path | None]:
return list(filter(lambda x: x is not None, map(make_path, paths)))
def make_paths(
paths: Sequence[GeneralPath], resolve: bool = False
) -> list[Path | None]:
return list(
filter(
lambda x: x is not None, map(lambda p: make_path(p, resolve=resolve), paths)
)
)


def subprocess_pipe_run(args: list[str]):
subprocess.run(
args,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
check=True,
)


def subprocess_quiet_run(args: list[str]):
Expand Down Expand Up @@ -145,6 +163,14 @@ class Extern7z:
def __init__(self, sevenz_exec: GeneralPathUnwrapped = "7z"):
self.sevenz_exec = str(sevenz_exec)

def check_sevenz_availability(self) -> bool:
try:
subprocess_pipe_run([self.sevenz_exec, "--help"])
return True
except Exception:
pure_log(f'[yellow]警告:设定的 7z 路径或别称 "{self.sevenz_exec}" 不合法或不存在,将使用默认模块处理压缩文档。')
return False

def _make_args_a(
self, zipfile: GeneralPathUnwrapped, filelist: Sequence[GeneralPath]
):
Expand Down Expand Up @@ -190,7 +216,7 @@ def make_archive(
if root_dir is not None:
_root_dir = make_path(root_dir)
assert _root_dir is not None
filelist = make_paths(list(_root_dir.rglob("*.*")))
filelist = make_paths(list(_root_dir.rglob("*.*")), resolve=False)

self._make_args_a(zipfile=_zipfile, filelist=filelist)
sevenz_args = self.sevenz_a_args
Expand Down Expand Up @@ -238,12 +264,12 @@ def check_if_path_string_valid(
path = Path(path_string)
if not path.exists():
if check_only:
print(f"警告{path_string} 路径指向的文件夹不存在。")
print(f"[red]警告[/]{path_string} 路径指向的文件夹不存在。")
return None

if not force_create:
create_folder = Prompt.ask(
f"警告{path_string} 路径指向的文件夹不存在,您想要创建吗?",
f"[red]警告[/]{path_string} 路径指向的文件夹不存在,您想要创建吗?",
choices=["y", "n"],
default="n",
)
Expand All @@ -256,15 +282,15 @@ def check_if_path_string_valid(
path.mkdir(parents=True, exist_ok=True)
return path
elif path.is_file():
print("警告:该路径指向一个已存在的文件。")
print("[red]警告[/]:该路径指向一个已存在的文件。")
return None
elif not os.access(path, os.R_OK):
print("警告:该路径指向一个已存在的文件夹,但访问受限或被拒绝。")
print("[red]警告[/]:该路径指向一个已存在的文件夹,但访问受限或被拒绝。")
return None
else:
return path
except Exception as e:
print(f"警告{e}")
print(f"[red]警告[/]{e}")
return None


Expand Down Expand Up @@ -324,9 +350,9 @@ def _tree(self, paths: dict, prefix: str = "", first: bool = True):
pointers = [self.tee] * (len(paths) - 1) + [self.last]
for pointer, path in zip(pointers, paths):
if first:
yield prefix + f"\033[34m{path}\033[0m"
yield f"{prefix}[blue]{path}[/]"
else:
yield prefix + pointer + f"\033[34m{path}\033[0m"
yield f"{prefix}{pointer}[blue]{path}[/]"
if isinstance(paths[path], dict): # extend the prefix and recurse:
if first:
extension = ""
Expand Down
90 changes: 57 additions & 33 deletions moe_utils/manga_repacker.py
Original file line number Diff line number Diff line change
@@ -1,41 +1,42 @@
import zipfile
from argparse import Namespace
from io import TextIOWrapper
import tomllib
from pathlib import Path
from argparse import Namespace
from typing import NamedTuple
import zipfile

import tomllib
from rich.console import Console, OverflowMethod

from tenacity import (
retry,
retry_if_exception_type,
stop_after_attempt,
stop_after_delay,
)

from .comic_info import ComicInfoExtractor
from .file_system import (
Extern7z,
GeneralPath,
GeneralPathUnwrapped,
PrettyDirectoryTree,
check_if_path_string_valid,
copy_dir_struct,
copy_dir_struct_to_list,
copy_dir_struct_ext_to_list,
copy_dir_struct_to_list,
copy_file_timestamp,
make_archive_threadsafe,
remove_if_exists,
unpack_archive_with_timestamp,
PrettyDirectoryTree,
)

from .terminal_ui import log as tui_log, PathTable
from .comic_info import ComicInfoExtractor
from .terminal_ui import PathTable
from .terminal_ui import log as tui_log


class ComicFile:
src_file: Path
dst_file: Path
cache_folder: Path
relative_path: Path

def __init__(
self,
Expand All @@ -49,9 +50,9 @@ def __init__(
assert out_dir is not None
assert cache_dir is not None
self.src_file = file_path
relative_path = file_path.relative_to(in_dir)
self.dst_file = out_dir / relative_path.with_suffix(".cbz")
self.cache_folder = cache_dir / relative_path.with_suffix("")
self.relative_path = file_path.relative_to(in_dir)
self.dst_file = out_dir / self.relative_path.with_suffix(".cbz")
self.cache_folder = cache_dir / self.relative_path.with_suffix("")


class InitValidityChecker(NamedTuple):
Expand Down Expand Up @@ -87,18 +88,29 @@ def __init__(
sevenz: Extern7z | GeneralPath = None,
):
self.verbose = verbose

if console is not None:
self.init_console(console)

if sevenz is not None:
self._use_extern_7z = True
if isinstance(sevenz, Extern7z):
self._extern_7z = sevenz
else:
self._extern_7z = Extern7z(sevenz)
self.init_sevenz(sevenz)

def init_console(self, console: Console):
self.console = console

def init_sevenz(self, sevenz: Extern7z | GeneralPathUnwrapped):
if isinstance(sevenz, Extern7z):
self._extern_7z = sevenz
elif isinstance(sevenz, GeneralPath):
self._extern_7z = Extern7z(sevenz)

if self._extern_7z is None:
self._use_extern_7z = False
elif not self._extern_7z.check_sevenz_availability():
self._use_extern_7z = False
else:
self._use_extern_7z = True

def print(self, s, *, overflow: OverflowMethod = "fold"):
self.console.print(s, overflow=overflow)

Expand All @@ -113,6 +125,7 @@ class Repacker(IRepacker):
_cache_dir: Path | None = None
_exclude_list: list[str] = []
_filelist: list[ComicFile] = []
_faillist: list[ComicFile] = []

def __init__(self, verbose: bool = True, console: Console | None = None):
super().__init__(verbose, console=console, sevenz=None)
Expand Down Expand Up @@ -173,17 +186,20 @@ def init_from_config(self, config_path: str):
self._cache_dir = cache_dir_obj
self._exclude_list = config["DEFAULT"]["Exclude"]

self._use_extern_7z = config["DEFAULT"]["UseExtern7z"]
if self._use_extern_7z:
def _set_use_extern_7z_switch() -> bool:
use_extern_7z: bool = config["DEFAULT"]["UseExtern7z"]
if not use_extern_7z:
return False
sevenz_exec: str = config["DEFAULT"]["Extern7zExec"]
if (
check_if_path_string_valid(
sevenz_exec, check_only=True, force_create=False
)
is None
):
sevenz_exec = "7z"
self._extern_7z = Extern7z(sevenz_exec)
use_extern_7z = self._extern_7z.check_sevenz_availability()
if use_extern_7z:
return True
self._extern_7z = Extern7z()
use_extern_7z = self._extern_7z.check_sevenz_availability()
return use_extern_7z

self._use_extern_7z = _set_use_extern_7z_switch()

def check_init_validity(self) -> InitValidityChecker:
if self._input_dir is None:
Expand Down Expand Up @@ -213,17 +229,25 @@ def cache_dir(self) -> str:
def filelist(self) -> list[ComicFile]:
return self._filelist

@property
def faillist(self) -> list[ComicFile]:
return self._faillist

def repack(self, file_t: ComicFile):
sevenz: Extern7z | None = None
if self._use_extern_7z:
sevenz = self._extern_7z
single_repacker = SingleRepacker(
comic_file=file_t,
console=self.console,
verbose=self.verbose,
sevenz=sevenz,
)
single_repacker.pack_folder()
try:
single_repacker = SingleRepacker(
comic_file=file_t,
console=self.console,
verbose=self.verbose,
sevenz=sevenz,
)
single_repacker.pack_folder()
except Exception as e:
self.log(f"[red]错误[/]:{e}")
self._faillist.append(file_t)

def print_list(self):
def new_comic_path(file_t: ComicFile) -> Path:
Expand Down
9 changes: 4 additions & 5 deletions moe_utils/progress_bar.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
from rich.progress import (
Progress,
Task,
ProgressColumn,
TextColumn,
BarColumn,
MofNCompleteColumn,
Progress,
ProgressColumn,
SpinnerColumn,
Task,
TextColumn,
TimeElapsedColumn,
TimeRemainingColumn,
)

from rich.text import Text


Expand Down
2 changes: 1 addition & 1 deletion moe_utils/taskbar_indicator.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import importlib
import time
import platform
import time
from functools import wraps


Expand Down
6 changes: 5 additions & 1 deletion moe_utils/terminal_ui.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from rich import print as rich_print
from rich.box import DOUBLE
from rich.panel import Panel
from rich.table import Table

from .utils import curr_time_format


welcome_panel = Panel.fit(
"[bold cyan]支持 [green][link=https://vol.moe]Vol.moe[/link][/] & [green][link=https://mox.moe]Mox.moe[/link][/] & "
"[green][link=https://kox.moe]Kox.moe[/link][/] 下载的漫画文件转换。[/] ",
Expand Down Expand Up @@ -36,3 +36,7 @@ def __init__(self, input_dir: str, output_dir: str, cache_dir: str):

def log(console, s: str, overflow="fold"):
console.print(f"[blue][{curr_time_format()}][/] {s}", overflow=overflow)


def pure_log(s: str):
rich_print(f"[blue][{curr_time_format()}][/] {s}")
Loading

0 comments on commit c10d10c

Please sign in to comment.