From f42de906e9b61e2307ce8a3f72e6fa4ff0f53d4c Mon Sep 17 00:00:00 2001 From: BuriedInCode <6057651+Buried-In-Code@users.noreply.github.com> Date: Mon, 20 May 2024 15:49:52 +1200 Subject: [PATCH] Service order adjustments (#15) - Set service order, fixes #14 - Only process necessary archives --- perdoo/__init__.py | 1 + perdoo/__main__.py | 67 +++++++++++++++++++++++++++++---------- perdoo/archives/cb7.py | 4 ++- perdoo/archives/cbt.py | 4 ++- perdoo/archives/cbz.py | 4 ++- perdoo/services/marvel.py | 4 +-- perdoo/settings.py | 29 +++++++++++++++++ 7 files changed, 91 insertions(+), 22 deletions(-) diff --git a/perdoo/__init__.py b/perdoo/__init__.py index 597fa62..8ae966d 100644 --- a/perdoo/__init__.py +++ b/perdoo/__init__.py @@ -64,6 +64,7 @@ def setup_logging(debug: bool = False) -> None: console_handler.setLevel(logging.DEBUG if debug else logging.INFO) console_handler.setFormatter(logging.Formatter("%(message)s")) file_handler = logging.FileHandler(filename=log_folder / "perdoo.log") + file_handler.setLevel(logging.DEBUG) logging.basicConfig( format="[%(asctime)s] [%(levelname)-8s] {%(name)s} | %(message)s", datefmt="%Y-%m-%d %H:%M:%S", diff --git a/perdoo/__main__.py b/perdoo/__main__.py index a0126a7..2c3a40f 100644 --- a/perdoo/__main__.py +++ b/perdoo/__main__.py @@ -19,7 +19,7 @@ from perdoo.models.metadata import Format, Meta, Source, Tool from perdoo.models.metron_info import InformationSource from perdoo.services import Comicvine, League, Marvel, Metron -from perdoo.settings import OutputFormat, Settings +from perdoo.settings import OutputFormat, Service, Settings from perdoo.utils import Details, Identifications, get_metadata_id, list_files, sanitize LOGGER = logging.getLogger("perdoo") @@ -47,7 +47,7 @@ def convert_collection(path: Path, output: OutputFormat) -> None: archive_type.convert(old_archive=archive) -def read_meta(archive: BaseArchive) -> tuple[Meta, Details]: +def read_meta(archive: BaseArchive) -> tuple[Meta | None, Details | None]: filenames = archive.list_filenames() def read_meta_file(cls: type[InfoModel], filename: str) -> InfoModel | None: @@ -55,6 +55,7 @@ def read_meta_file(cls: type[InfoModel], filename: str) -> InfoModel | None: return cls.from_bytes(content=archive.read_file(filename=filename)) return None + # region Read Metadata try: metadata = read_meta_file(cls=Metadata, filename="/Metadata.xml") or read_meta_file( cls=Metadata, filename="Metadata.xml" @@ -97,6 +98,9 @@ def read_meta_file(cls: type[InfoModel], filename: str) -> InfoModel | None: return meta, details except ValidationError: LOGGER.error("%s contains an invalid Metadata file", archive.path.name) # noqa: TRY400 + # endregion + + # region Read MetronInfo try: metron_info = read_meta_file(cls=MetronInfo, filename="/MetronInfo.xml") or read_meta_file( cls=MetronInfo, filename="MetronInfo.xml" @@ -139,6 +143,9 @@ def read_meta_file(cls: type[InfoModel], filename: str) -> InfoModel | None: return Meta(date_=date.today(), tool=Tool(value="MetronInfo")), details except ValidationError: LOGGER.error("%s contains an invalid MetronInfo file", archive.path.name) # noqa: TRY400 + # endregion + + # region Read ComicInfo try: comic_info = read_meta_file(cls=ComicInfo, filename="/ComicInfo.xml") or read_meta_file( cls=ComicInfo, filename="ComicInfo.xml" @@ -151,11 +158,28 @@ def read_meta_file(cls: type[InfoModel], filename: str) -> InfoModel | None: return Meta(date_=date.today(), tool=Tool(value="ComicInfo")), details except ValidationError: LOGGER.error("%s contains an invalid ComicInfo file", archive.path.name) # noqa: TRY400 - - return Meta(date_=date.today(), tool=Tool(value="Manual")), Details( - series=Identifications(search=Prompt.ask("Series title", console=CONSOLE)), - issue=Identifications(), - ) + # endregion + + return None, None + + +def load_archives( + path: Path, output: OutputFormat, force: bool = False +) -> list[tuple[Path, BaseArchive, Details | None]]: + archives = [] + with CONSOLE.status(f"Searching for {output} files"): + for file in list_files(path, f".{output}"): + archive = get_archive(path=file) + LOGGER.debug("Reading %s", file.stem) + meta, details = read_meta(archive=archive) + if not meta or not details: + archives.append((file, archive, details)) + continue + difference = abs(date.today() - meta.date_) + if force or meta.tool != Tool() or difference.days >= 28: + archives.append((file, archive, details)) + continue + return archives def fetch_from_services( @@ -181,7 +205,15 @@ def fetch_from_services( LOGGER.warning("No external services configured") return None, None, None - for service in (marvel, metron, comicvine, league): + services = { + Service.COMICVINE: comicvine, + Service.LEAGUE_OF_COMIC_GEEKS: league, + Service.MARVEL: marvel, + Service.METRON: metron, + } + + for service_name in settings.service_order: + service = services[service_name] if not service: continue LOGGER.info("Fetching details from %s", type(service).__name__) @@ -243,6 +275,7 @@ def process_pages( from perdoo.models.metadata import Page as MetadataPage from perdoo.models.metron_info import Page as MetronPage + LOGGER.info("Processing pages") rename_images(folder=folder, filename=filename) image_list = list_files(folder, *IMAGE_EXTENSIONS) metadata_pages = set() @@ -272,16 +305,17 @@ def process_pages( def start(settings: Settings, force: bool = False) -> None: LOGGER.info("Starting Perdoo") convert_collection(path=settings.collection_folder, output=settings.output.format) - for file in list_files(settings.collection_folder, f".{settings.output.format}"): - archive = get_archive(path=file) + archives = load_archives( + path=settings.collection_folder, output=settings.output.format, force=force + ) + + for file, archive, details in archives: CONSOLE.rule(file.stem) LOGGER.info("Processing %s", file.stem) - meta, details = read_meta(archive=archive) - - if not force: - difference = abs(date.today() - meta.date_) - if meta.tool == Tool() and difference.days < 28: - continue + details = details or Details( # noqa: PLW2901 + series=Identifications(search=Prompt.ask("Series title", console=CONSOLE)), + issue=Identifications(), + ) metadata, metron_info, comic_info = fetch_from_services(settings=settings, details=details) new_file = generate_filename( @@ -293,7 +327,6 @@ def start(settings: Settings, force: bool = False) -> None: temp_folder = Path(temp_str) if not archive.extract_files(destination=temp_folder): return - LOGGER.info("Processing %s pages", file.stem) process_pages( folder=temp_folder, metadata=metadata, diff --git a/perdoo/archives/cb7.py b/perdoo/archives/cb7.py index a14e6a2..0b786ec 100644 --- a/perdoo/archives/cb7.py +++ b/perdoo/archives/cb7.py @@ -78,7 +78,9 @@ def convert(old_archive: BaseArchive) -> CB7Archive | None: temp_folder = Path(temp_str) if not old_archive.extract_files(destination=temp_folder): return None - archive_file = CB7Archive.archive_files(src=temp_folder, filename=old_archive.path.stem) + archive_file = CB7Archive.archive_files( + src=temp_folder, output_name=old_archive.path.stem + ) if not archive_file: return None new_filepath = old_archive.path.parent / f"{old_archive.path.stem}.cb7" diff --git a/perdoo/archives/cbt.py b/perdoo/archives/cbt.py index 683b9ad..0dd9df4 100644 --- a/perdoo/archives/cbt.py +++ b/perdoo/archives/cbt.py @@ -73,7 +73,9 @@ def convert(old_archive: BaseArchive) -> CBTArchive | None: temp_folder = Path(temp_str) if not old_archive.extract_files(destination=temp_folder): return None - archive_file = CBTArchive.archive_files(src=temp_folder, filename=old_archive.path.stem) + archive_file = CBTArchive.archive_files( + src=temp_folder, output_name=old_archive.path.stem + ) if not archive_file: return None new_filepath = old_archive.path.parent / f"{old_archive.path.stem}.cbt" diff --git a/perdoo/archives/cbz.py b/perdoo/archives/cbz.py index bdc3289..63b1295 100644 --- a/perdoo/archives/cbz.py +++ b/perdoo/archives/cbz.py @@ -61,7 +61,9 @@ def convert(old_archive: BaseArchive) -> CBZArchive | None: temp_folder = Path(temp_str) if not old_archive.extract_files(destination=temp_folder): return None - archive_file = CBZArchive.archive_files(src=temp_folder, filename=old_archive.path.stem) + archive_file = CBZArchive.archive_files( + src=temp_folder, output_name=old_archive.path.stem + ) if not archive_file: return None new_filepath = old_archive.path.parent / f"{old_archive.path.stem}.cbz" diff --git a/perdoo/services/marvel.py b/perdoo/services/marvel.py index 25b0e91..935af5c 100644 --- a/perdoo/services/marvel.py +++ b/perdoo/services/marvel.py @@ -25,7 +25,7 @@ class Marvel(BaseService[Series, Comic]): def __init__(self: Marvel, settings: MarvelSettings): - cache = SqliteCache(db_name=str(get_cache_dir() / "mokkari.sqlite"), expire=14) + cache = SqliteCache(db_name=str(get_cache_dir() / "esak.sqlite"), expire=14) self.session = Esak( public_key=settings.public_key, private_key=settings.private_key, cache=cache ) @@ -40,7 +40,7 @@ def _get_series_id(self: Marvel, title: str | None) -> int | None: if not options: LOGGER.warning("Unable to find any Series with the title: '%s'", title) index = create_menu( - options=[f"{x.id} | {x.title} ({x.start_year})" for x in options], + options=[f"{x.id} | {x.title}" for x in options], title="Marvel Series", default="None of the Above", ) diff --git a/perdoo/settings.py b/perdoo/settings.py index 2dd361f..80d9727 100644 --- a/perdoo/settings.py +++ b/perdoo/settings.py @@ -77,6 +77,28 @@ def __str__(self: OutputFormat) -> str: return self.value +class Service(Enum): + COMICVINE = "Comicvine" + LEAGUE_OF_COMIC_GEEKS = "League of Comic Geeks" + MARVEL = "Marvel" + METRON = "Metron" + + @staticmethod + def load(value: str) -> Service: + for entry in Service: + if entry.value.casefold() == value.casefold(): + return entry + raise ValueError(f"`{value}` isn't a valid Service") + + def __lt__(self: Service, other) -> int: # noqa: ANN001 + if not isinstance(other, type(self)): + raise NotImplementedError + return self.value < other.value + + def __str__(self: Service) -> str: + return self.value + + class Output(SettingsModel): create_comic_info: bool = True create_metron_info: bool = True @@ -99,6 +121,12 @@ class Settings(SettingsModel): league_of_comic_geeks: LeagueofComicGeeks = LeagueofComicGeeks() marvel: Marvel = Marvel() metron: Metron = Metron() + service_order: list[Service] = [ + Service.METRON, + Service.MARVEL, + Service.COMICVINE, + Service.LEAGUE_OF_COMIC_GEEKS, + ] output: Output = Output() @classmethod @@ -113,6 +141,7 @@ def save(self: Settings) -> Settings: with self._filename.open("wb") as stream: content = self.dict(by_alias=False) content["collection_folder"] = str(content["collection_folder"]) + content["service_order"] = [str(x) for x in content["service_order"]] content["output"]["format"] = str(content["output"]["format"]) tomlwriter.dump(content, stream) return self