62 lines
1.8 KiB
Python
62 lines
1.8 KiB
Python
from io import BytesIO
|
|
from pathlib import Path
|
|
import zipfile
|
|
|
|
import rarfile
|
|
from PIL import Image, ImageOps
|
|
|
|
SUPPORTED_IMG = {".jpg", ".jpeg", ".png", ".webp", ".gif", ".bmp"}
|
|
|
|
|
|
|
|
def _is_cbz(path: Path) -> bool:
|
|
return path.suffix.lower() == ".cbz"
|
|
|
|
|
|
def cbr_page_list(path: Path) -> list[str]:
|
|
if _is_cbz(path):
|
|
with zipfile.ZipFile(path) as zf:
|
|
names = [n for n in zf.namelist() if Path(n).suffix.lower() in SUPPORTED_IMG]
|
|
else:
|
|
with rarfile.RarFile(path) as rf:
|
|
names = [n for n in rf.namelist() if Path(n).suffix.lower() in SUPPORTED_IMG]
|
|
return sorted(names)
|
|
|
|
|
|
def cbr_page_count(path: Path) -> int:
|
|
return len(cbr_page_list(path))
|
|
|
|
|
|
def cbr_get_page(path: Path, page_num: int) -> tuple[bytes, str]:
|
|
pages = cbr_page_list(path)
|
|
if page_num < 0 or page_num >= len(pages):
|
|
raise IndexError("Page out of range")
|
|
name = pages[page_num]
|
|
ext = Path(name).suffix.lower().lstrip(".")
|
|
mime = {
|
|
"jpg": "image/jpeg",
|
|
"jpeg": "image/jpeg",
|
|
"png": "image/png",
|
|
"webp": "image/webp",
|
|
"gif": "image/gif",
|
|
"bmp": "image/bmp",
|
|
}.get(ext, "image/jpeg")
|
|
|
|
if _is_cbz(path):
|
|
with zipfile.ZipFile(path) as zf:
|
|
return zf.read(name), mime
|
|
with rarfile.RarFile(path) as rf:
|
|
return rf.read(name), mime
|
|
|
|
|
|
def cbr_cover_thumb(path: Path) -> bytes:
|
|
data, _ = cbr_get_page(path, 0)
|
|
with Image.open(BytesIO(data)) as im:
|
|
im = ImageOps.exif_transpose(im)
|
|
if im.mode not in ("RGB", "RGBA"):
|
|
im = im.convert("RGB")
|
|
thumb = ImageOps.fit(im, (300, 450), method=Image.Resampling.LANCZOS)
|
|
out = BytesIO()
|
|
thumb.save(out, format="WEBP", quality=82, method=6)
|
|
return out.getvalue()
|