Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,13 @@ Unlike other tagging tools, Perdoo employs a manual approach when metadata files
- .cbr
- .cbt
- .cbz
- .cb7 _(Requires installing `cb7` dependencies: `pipx install perdoo[cb7]`)_
- .cb7

### Output Extensions

- .cbt
- .cbz _(Default)_
- .cb7 _(Requires installing `cb7` dependencies: `pipx install perdoo[cb7]`)_
- .cb7

### Metadata Files

Expand Down
22 changes: 9 additions & 13 deletions perdoo/archives/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from tarfile import is_tarfile
from zipfile import is_zipfile

from py7zr import is_7zfile
from rarfile import is_rarfile

from perdoo.archives._base import BaseArchive
Expand All @@ -20,13 +21,6 @@
from perdoo.archives.cbt import CBTArchive
from perdoo.archives.cbz import CBZArchive

try:
from py7zr import is_7zfile

py7zr_loaded = True
except ImportError:
py7zr_loaded = False


def get_archive(path: Path) -> BaseArchive:
if is_zipfile(path):
Expand All @@ -35,15 +29,17 @@ def get_archive(path: Path) -> BaseArchive:
return CBRArchive(path=path)
if is_tarfile(path):
return CBTArchive(path=path)
if py7zr_loaded and is_7zfile:
if is_7zfile(path):
return CB7Archive(path=path)
raise NotImplementedError(f"{path.name} is an unsupported archive")


def get_archive_class(extension: str) -> type[BaseArchive]:
archive_types = {"cbz": CBZArchive, "cbr": CBRArchive, "cbt": CBTArchive}
if extension == "cb7" and py7zr_loaded:
return CB7Archive
if extension in archive_types:
return archive_types[extension]
if archive_class := {
"cbz": CBZArchive,
"cbr": CBRArchive,
"cbt": CBTArchive,
"cb7": CB7Archive,
}.get(extension):
return archive_class
raise NotImplementedError(f"{extension} is an unsupported archive")
36 changes: 10 additions & 26 deletions perdoo/archives/cb7.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,70 +6,54 @@
from tempfile import TemporaryDirectory
from typing import Optional

from py7zr import Bad7zFile, SevenZipFile

from perdoo.archives._base import BaseArchive
from perdoo.utils import list_files

try:
import py7zr

py7zr_loaded = True
except ImportError:
py7zr_loaded = False

LOGGER = logging.getLogger(__name__)


class CB7Archive(BaseArchive):
def __init__(self, path: Path):
if not py7zr_loaded:
raise ImportError("Install Perdoo with the cb7 dependency group to use CB7 files.")
super().__init__(path=path)

def list_filenames(self) -> list[str]:
try:
with py7zr.SevenZipFile(self.path, "r") as archive:
with SevenZipFile(self.path, "r") as archive:
return archive.getnames()
except py7zr.Bad7zFile:
except Bad7zFile:
LOGGER.exception("Unable to read %s", self.path.name)
return []

def read_file(self, filename: str) -> bytes:
try:
with py7zr.SevenZipFile(self.path, "r") as archive, archive.open(filename) as file:
with SevenZipFile(self.path, "r") as archive, archive.open(filename) as file:
return file.read()
except (py7zr.Bad7zFile, KeyError):
except (Bad7zFile, KeyError):
LOGGER.exception("Unable to read %s", self.path.name)
return b""

def extract_files(self, destination: Path) -> bool:
try:
with py7zr.SevenZipFile(self.path, "r") as archive:
with SevenZipFile(self.path, "r") as archive:
archive.extractall(path=destination)
return True
except py7zr.Bad7zFile:
except Bad7zFile:
LOGGER.exception("")
return False

@classmethod
def archive_files(cls, src: Path, output_name: str, files: list[Path]) -> Path | None:
if not py7zr_loaded:
raise ImportError("Install Perdoo with the cb7 dependency group to use CB7 files.")

output_file = src.parent / f"{output_name}.cb7"
try:
with py7zr.SevenZipFile(output_file, "w") as archive:
with SevenZipFile(output_file, "w") as archive:
for file in files:
archive.write(file, arcname=file.name)
return output_file
except py7zr.Bad7zFile:
except Bad7zFile:
LOGGER.exception("")
return None

@staticmethod
def convert(old_archive: BaseArchive) -> Optional["CB7Archive"]:
if not py7zr_loaded:
raise ImportError("Install Perdoo with the cb7 dependency group to use CB7 files.")

with TemporaryDirectory(prefix=f"{old_archive.path.stem}_") as temp_str:
temp_folder = Path(temp_str)
if not old_archive.extract_files(destination=temp_folder):
Expand Down
21 changes: 2 additions & 19 deletions perdoo/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,11 @@
]

from enum import Enum
from importlib.util import find_spec
from pathlib import Path
from typing import Any, ClassVar, Literal

import tomli_w as tomlwriter
from pydantic import BaseModel, field_validator
from pydantic import BaseModel
from rich.panel import Panel

from perdoo import get_config_root, get_data_root
Expand Down Expand Up @@ -59,12 +58,6 @@ class Output(SettingsModel):
format: Literal["cb7", "cbt", "cbz"] = "cbz"
metadata: Metadata = Metadata()

@field_validator("format", mode="before")
def validate_format(cls, value: str) -> str:
if value == "cb7" and find_spec("py7zr") is None:
raise ImportError("Install Perdoo with the cb7 dependency group to use CB7 files.")
return value


class Comicvine(SettingsModel):
api_key: str | None = None
Expand All @@ -80,21 +73,11 @@ class Metron(SettingsModel):
username: str | None = None


class Service(Enum):
class Service(str, Enum):
COMICVINE = "Comicvine"
MARVEL = "Marvel"
METRON = "Metron"

@staticmethod
def load(value: str) -> "Service":
for entry in Service:
if entry.value.replace(" ", "").casefold() == value.replace(" ", "").casefold():
return entry
raise ValueError(f"'{value}' isn't a valid Service")

def __str__(self) -> str:
return self.value


class Services(SettingsModel):
comicvine: Comicvine = Comicvine()
Expand Down
6 changes: 1 addition & 5 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ dependencies = [
"mokkari >= 3.5.0",
"natsort >= 8.4.0",
"pillow >= 11.0.0",
"py7zr >= 0.22.0",
"pydantic >= 2.10.4",
"pydantic-xml >= 2.14.1",
"rarfile >= 4.2",
Expand All @@ -57,11 +58,6 @@ name = "perdoo"
readme = "README.md"
requires-python = ">= 3.10"

[project.optional-dependencies]
cb7 = [
"py7zr >= 0.22.0"
]

[project.scripts]
Perdoo = "perdoo.__main__:app"

Expand Down
Loading