Ivan Schaller
e0cabe6b9f
All checks were successful
ci/woodpecker/push/tests Pipeline was successful
ci/woodpecker/pr/tests Pipeline was successful
ci/woodpecker/pr/test_docker_arm64 Pipeline was successful
ci/woodpecker/pr/test_docker_amd64 Pipeline was successful
ci/woodpecker/pr/test_release Pipeline was successful
ci/woodpecker/pr/test_tox_arm64 Pipeline was successful
ci/woodpecker/pr/test_tox_amd64 Pipeline was successful
163 lines
5.8 KiB
Python
163 lines
5.8 KiB
Python
import re
|
|
from datetime import datetime
|
|
from pathlib import Path
|
|
from typing import Any
|
|
from zipfile import ZipFile
|
|
|
|
from loguru import logger as log
|
|
|
|
|
|
# create an archive of the chapter images
|
|
def make_archive(chapter_path: Path, file_format: str) -> None:
|
|
zip_path: Path = Path(f"{chapter_path}.zip")
|
|
try:
|
|
# create zip
|
|
with ZipFile(zip_path, "w") as zipfile:
|
|
for file in chapter_path.iterdir():
|
|
zipfile.write(file, file.name)
|
|
# rename zip to file format requested
|
|
zip_path.replace(zip_path.with_suffix(file_format))
|
|
except Exception as exc:
|
|
log.error(f"Can't create '{file_format}' archive")
|
|
raise exc
|
|
|
|
|
|
def make_pdf(chapter_path: Path) -> None:
|
|
try:
|
|
import img2pdf # pylint: disable=import-outside-toplevel
|
|
except Exception as exc:
|
|
log.error("Cant import img2pdf. Please install it first")
|
|
raise exc
|
|
|
|
pdf_path: Path = Path(f"{chapter_path}.pdf")
|
|
images: list[str] = []
|
|
for file in chapter_path.iterdir():
|
|
images.append(str(file))
|
|
try:
|
|
pdf_path.write_bytes(img2pdf.convert(images))
|
|
except Exception as exc:
|
|
log.error("Can't create '.pdf' archive")
|
|
raise exc
|
|
|
|
|
|
# create a list of chapters
|
|
def get_chapter_list(chapters: str, available_chapters: list) -> list:
|
|
# check if there are available chapter
|
|
chapter_list: list[str] = []
|
|
for chapter in chapters.split(","):
|
|
# check if chapter list is with volumes and ranges (forcevol)
|
|
if "-" in chapter and ":" in chapter:
|
|
# split chapters and volumes apart for list generation
|
|
lower_num_fv: list[str] = chapter.split("-")[0].split(":")
|
|
upper_num_fv: list[str] = chapter.split("-")[1].split(":")
|
|
vol_fv: str = lower_num_fv[0]
|
|
chap_beg_fv: int = int(lower_num_fv[1])
|
|
chap_end_fv: int = int(upper_num_fv[1])
|
|
# generate range inbetween start and end --> 1:1-1:3 == 1:1,1:2,1:3
|
|
for chap in range(chap_beg_fv, chap_end_fv + 1):
|
|
chapter_list.append(str(f"{vol_fv}:{chap}"))
|
|
# no volumes, just chapter ranges
|
|
elif "-" in chapter:
|
|
lower_num: int = int(chapter.split("-")[0])
|
|
upper_num: int = int(chapter.split("-")[1])
|
|
# generate range inbetween start and end --> 1-3 == 1,2,3
|
|
for chap in range(lower_num, upper_num + 1):
|
|
chapter_list.append(str(chap))
|
|
# check if full volume should be downloaded
|
|
elif ":" in chapter:
|
|
vol_num: str = chapter.split(":")[0]
|
|
chap_num: str = chapter.split(":")[1]
|
|
# select all chapters from the volume --> 1: == 1:1,1:2,1:3...
|
|
if vol_num and not chap_num:
|
|
regex: Any = re.compile(f"{vol_num}:[0-9]{{1,4}}")
|
|
vol_list: list[str] = [n for n in available_chapters if regex.match(n)]
|
|
chapter_list.extend(vol_list)
|
|
else:
|
|
chapter_list.append(chapter)
|
|
# single chapters without a range given
|
|
else:
|
|
chapter_list.append(chapter)
|
|
|
|
return chapter_list
|
|
|
|
|
|
# remove illegal characters etc
|
|
def fix_name(filename: str) -> str:
|
|
log.debug(f"Input name='{filename}'")
|
|
filename = filename.encode(encoding="utf8", errors="ignore").decode(encoding="utf8")
|
|
# remove illegal characters
|
|
filename = re.sub(r'[/\\<>:;|?*!@"]', "", filename)
|
|
# remove multiple dots
|
|
filename = re.sub(r"([.]{2,})", ".", filename)
|
|
# remove dot(s) at the beginning and end of the filename
|
|
filename = re.sub(r"(^[.]+)|([.]+$)", "", filename)
|
|
# remove trailing and beginning spaces
|
|
filename = re.sub("([ \t]+$)|(^[ \t]+)", "", filename)
|
|
|
|
log.debug(f"Output name='{filename}'")
|
|
return filename
|
|
|
|
|
|
# create name for chapter
|
|
def get_filename(
|
|
manga_title: str,
|
|
chapter_name: str,
|
|
chapter_vol: str,
|
|
chapter_num: str,
|
|
forcevol: bool,
|
|
name_format: str,
|
|
name_format_none: str,
|
|
) -> str:
|
|
# try to apply the custom format
|
|
if name_format != "{default}":
|
|
log.debug(f"Using custom name format: '{name_format}'")
|
|
try:
|
|
filename = name_format.format(
|
|
manga_title=manga_title or name_format_none,
|
|
chapter_name=chapter_name or name_format_none,
|
|
chapter_vol=chapter_vol or name_format_none,
|
|
chapter_num=chapter_num or name_format_none,
|
|
)
|
|
except Exception:
|
|
log.warning("File format is not valid. Falling back to default")
|
|
else:
|
|
return filename
|
|
|
|
# set vol to 0 if none found
|
|
chapter_vol = chapter_vol or "0"
|
|
|
|
# use default format
|
|
log.debug("Using default name format")
|
|
# if chapter is a oneshot
|
|
if not chapter_num or "oneshot" in [chapter_name.lower(), chapter_num.lower()]:
|
|
return "Oneshot"
|
|
|
|
# if the chapter has no name
|
|
if not chapter_name and forcevol:
|
|
return f"Vol. {chapter_vol} Ch. {chapter_num}"
|
|
if not chapter_name:
|
|
return f"Ch. {chapter_num}"
|
|
|
|
# if the chapter has a name
|
|
# return with volume if option is set, else just the chapter num and name
|
|
if forcevol:
|
|
return f"Vol. {chapter_vol} Ch. {chapter_num} - {chapter_name}"
|
|
|
|
return f"Ch. {chapter_num} - {chapter_name}"
|
|
|
|
|
|
def progress_bar(progress: float, total: float) -> None:
|
|
time = datetime.now().strftime("%Y-%m-%dT%H:%M:%S")
|
|
percent = int(progress / (int(total) / 100))
|
|
bar_length = 50
|
|
bar_progress = int(progress / (int(total) / bar_length))
|
|
bar_texture = "■" * bar_progress
|
|
whitespace_texture = " " * (bar_length - bar_progress)
|
|
if progress == total:
|
|
full_bar = "■" * bar_length
|
|
print(f"\r{time}{' '*6}| [BAR ] ❙{full_bar}❙ 100%", end="\n")
|
|
else:
|
|
print(
|
|
f"\r{time}{' '*6}| [BAR ] ❙{bar_texture}{whitespace_texture}❙ {percent}%",
|
|
end="\r",
|
|
)
|