From c37c8e9f9a694352b781d047be594a7f92a219ab Mon Sep 17 00:00:00 2001 From: Brian Pepple Date: Sat, 30 Nov 2024 09:17:58 -0500 Subject: [PATCH] Add ComicInfo -> Metroninfo Migration Function (#160) * Add `migrate_ci_to_mi` function * Refactor title print functions * Add option for `migrate` * Require latest darkseid --- metrontagger/cli.py | 3 ++ metrontagger/options.py | 6 ++++ metrontagger/run.py | 72 +++++++++++++++++++++++++++++----------- metrontagger/settings.py | 1 + metrontagger/talker.py | 14 ++++---- metrontagger/utils.py | 17 ++++++++++ poetry.lock | 8 ++--- pyproject.toml | 2 +- 8 files changed, 91 insertions(+), 32 deletions(-) diff --git a/metrontagger/cli.py b/metrontagger/cli.py index 563c480..e9c0dce 100644 --- a/metrontagger/cli.py +++ b/metrontagger/cli.py @@ -82,6 +82,9 @@ def get_configs(opts: Namespace) -> MetronTaggerSettings: # noqa: PLR0912 if opts.comicinfo: config.use_comic_info = opts.comicinfo + if opts.migrate: + config.migrate = opts.migrate + return config diff --git a/metrontagger/options.py b/metrontagger/options.py index a43cbdc..73d8f03 100644 --- a/metrontagger/options.py +++ b/metrontagger/options.py @@ -106,6 +106,12 @@ def make_parser() -> argparse.ArgumentParser: action="store_true", default=False, ) + parser.add_argument( + "--migrate", + help="Migrate information from a ComicInfo.xml into a *new* MetronInfo.xml", + action="store_true", + default=False, + ) parser.add_argument( "--version", action="version", diff --git a/metrontagger/run.py b/metrontagger/run.py index 8ddf369..a9de046 100644 --- a/metrontagger/run.py +++ b/metrontagger/run.py @@ -15,6 +15,7 @@ from metrontagger.filerenamer import FileRenamer from metrontagger.filesorter import FileSorter from metrontagger.logging import init_logging +from metrontagger.utils import create_print_title if TYPE_CHECKING: from metrontagger.settings import MetronTaggerSettings @@ -40,6 +41,42 @@ def __init__(self: Runner, config: MetronTaggerSettings) -> None: self.config = config + @staticmethod + def migrate_ci_to_mi(file_list: list[Path]) -> None: + """ + Migrate ComicInfo.xml metadata to MetronInfo.xml format. + + This static method processes a list of comic files, checking for existing ComicInfo.xml metadata and + migrating it to the MetronInfo.xml format if applicable. It provides feedback on the migration process + through printed messages. + + Args: + file_list (list[Path]): A list of Path objects representing the comic files to be processed. + + Returns: + None + """ + + msg = create_print_title("Migrating ComicInfo.xml to MetronInfo.xml:") + questionary.print(msg, style=Styles.TITLE) + + for item in file_list: + comic = Comic(item) + if comic.has_metadata(MetadataFormat.COMIC_RACK) and not comic.has_metadata( + MetadataFormat.METRON_INFO + ): + md = comic.read_metadata(MetadataFormat.COMIC_RACK) + if comic.write_metadata(md, MetadataFormat.METRON_INFO): + questionary.print( + f"Migrated information to new MetronInfo.xml for '{comic}'", + style=Styles.SUCCESS, + ) + else: + questionary.print( + f"There was an error writing MetronInfo.xml for '{comic}'", + style=Styles.ERROR, + ) + def rename_comics(self: Runner, file_list: list[Path]) -> list[Path]: """Rename comic archives based on metadata. @@ -52,11 +89,8 @@ def rename_comics(self: Runner, file_list: list[Path]) -> list[Path]: Returns: list[Path]: The updated list of file paths after renaming. """ - - questionary.print( - "\nStarting comic archive renaming:\n-------------------------------", - style=Styles.TITLE, - ) + msg = create_print_title("Renaming ComicInfo.xml to MetronInfo.xml:") + questionary.print(msg, style=Styles.TITLE) # Lists to track filename changes new_file_names: list[Path] = [] @@ -113,8 +147,8 @@ def _export_to_zip(self: Runner, file_list: list[Path]) -> None: Returns: None """ - - questionary.print("\nExporting to cbz:\n-----------------", style=Styles.TITLE) + msg = create_print_title("Exporting to CBZ:") + questionary.print(msg, style=Styles.TITLE) for comic in file_list: ca = Comic(str(comic)) if ca.is_rar(): @@ -139,8 +173,8 @@ def _validate_comic_info( self: Runner, file_list: list[Path], remove_ci: bool = False ) -> None: """Validate ComicInfo metadata in comic archives.""" - - questionary.print("\nValidating ComicInfo:\n---------------------", style=Styles.TITLE) + msg = create_print_title("Validating ComicInfo:") + questionary.print(msg, style=Styles.TITLE) for comic in file_list: ca = Comic(comic) has_comic_rack = ca.has_metadata(MetadataFormat.COMIC_RACK) @@ -212,10 +246,8 @@ def _sort_comic_list(self: Runner, file_list: list[Path]) -> None: ) return - questionary.print( - "\nStarting sorting of comic archives:\n----------------------------------", - style=Styles.TITLE, - ) + msg = create_print_title("Starting Sorting of Comic Archives:") + questionary.print(msg, style=Styles.TITLE) file_sorter = FileSorter(self.config.sort_dir) for comic in file_list: result = file_sorter.sort_comics(comic) @@ -233,11 +265,8 @@ def _comics_with_no_metadata(self: Runner, file_list: list[Path]) -> None: Returns: None """ - - questionary.print( - "\nShowing files without metadata:\n-------------------------------", - style=Styles.TITLE, - ) + msg = create_print_title("Showing Files Without Metadata:") + questionary.print(msg, style=Styles.TITLE) if not (self.config.use_comic_info or self.config.use_metron_info): return @@ -264,8 +293,8 @@ def _delete_metadata(self: Runner, file_list: list[Path]) -> None: Returns: None """ - - questionary.print("\nRemoving metadata:\n-----------------", style=Styles.TITLE) + msg = create_print_title("Removing Metadata:") + questionary.print(msg, style=Styles.TITLE) for item in file_list: comic_archive = Comic(item) formats_removed = [] @@ -533,6 +562,9 @@ def run(self: Runner) -> None: # noqa: PLR0912 else: t.identify_comics(file_list, self.config) + if self.config.migrate: + self.migrate_ci_to_mi(file_list) + if self.config.rename: file_list = self.rename_comics(file_list) diff --git a/metrontagger/settings.py b/metrontagger/settings.py index 61514ad..97252f9 100644 --- a/metrontagger/settings.py +++ b/metrontagger/settings.py @@ -49,6 +49,7 @@ def __init__(self: MetronTaggerSettings, config_dir: str | None = None) -> None: self.validate: bool = False self.remove_non_valid: bool = False self.duplicates: bool = False + self.migrate: bool = False # Rename settings self.rename_template = "%series% v%volume% #%issue% (%year%)" diff --git a/metrontagger/talker.py b/metrontagger/talker.py index 8d55172..ed44a3d 100644 --- a/metrontagger/talker.py +++ b/metrontagger/talker.py @@ -39,7 +39,7 @@ from metrontagger import __version__ from metrontagger.styles import Styles -from metrontagger.utils import create_query_params +from metrontagger.utils import create_print_title, create_query_params LOGGER = getLogger(__name__) @@ -383,12 +383,14 @@ def _post_process_matches(self: Talker) -> None: """ # Print file matching results. if self.match_results.good_matches: - questionary.print("\nSuccessful matches:\n------------------", style=Styles.TITLE) + msg = create_print_title("Successful Matches:") + questionary.print(msg, style=Styles.TITLE) for comic in self.match_results.good_matches: questionary.print(f"{comic}", style=Styles.SUCCESS) if self.match_results.no_matches: - questionary.print("\nNo matches:\n------------------", style=Styles.TITLE) + msg = create_print_title("No Matches:") + questionary.print(msg, style=Styles.TITLE) for comic in self.match_results.no_matches: questionary.print(f"{comic}", style=Styles.WARNING) @@ -474,10 +476,8 @@ def identify_comics( Returns: None """ - questionary.print( - "\nStarting online search and tagging:\n----------------------------------", - style=Styles.TITLE, - ) + msg = create_print_title("Starting Online Search and Tagging:") + questionary.print(msg, style=Styles.TITLE) for fn in file_list: if config.ignore_existing: diff --git a/metrontagger/utils.py b/metrontagger/utils.py index 24efac4..d3c4364 100644 --- a/metrontagger/utils.py +++ b/metrontagger/utils.py @@ -3,6 +3,23 @@ from urllib.parse import quote_plus +def create_print_title(txt: str) -> str: + """Create a formatted title string for printing. + + This function generates a title string that includes the provided text, formatted with newlines + and a line of dashes beneath it for visual separation. It is useful for enhancing the readability + of printed output by clearly delineating sections. + + Args: + txt (str): The text to be used as the title. + + Returns: + str: The formatted title string, including newlines and dashes. + """ + result = f"\n{txt}\n" + return result + "-" * len(txt) + + def cleanup_string(path_name: int | str | None) -> str | None: """Clean up and sanitize a string for use as a path name. diff --git a/poetry.lock b/poetry.lock index 0c65b1a..b3ceb9c 100644 --- a/poetry.lock +++ b/poetry.lock @@ -287,13 +287,13 @@ toml = ["tomli"] [[package]] name = "darkseid" -version = "5.0.1" +version = "5.1.0" description = "A library to interact with comic archives" optional = false python-versions = "<4.0,>=3.10" files = [ - {file = "darkseid-5.0.1-py3-none-any.whl", hash = "sha256:bc6c24519553a903ca58c3f64509865e1a3d9417e0423a9aefa59d13423758b6"}, - {file = "darkseid-5.0.1.tar.gz", hash = "sha256:b1d607f391944315336df54f0f2de53bfad2d35bb6a8c687ac3be92b786478be"}, + {file = "darkseid-5.1.0-py3-none-any.whl", hash = "sha256:642c749cc705f7259c59b92f016b109c1ced3695c2e39e36e386c158efa4e16f"}, + {file = "darkseid-5.1.0.tar.gz", hash = "sha256:28a158345f639f64ce6781ec649e4a6fbd63f07b8ecd78bbcfc7bc754c86d38d"}, ] [package.dependencies] @@ -1532,4 +1532,4 @@ docs = ["Sphinx", "elementpath (>=4.4.0,<5.0.0)", "jinja2", "sphinx-rtd-theme"] [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "e0bdd5d3348e3d12c9531302f4daedd9c9ef8646af76af2b949017b9f2c7918e" +content-hash = "f9fa0457eacd780b5fe5faad8e7dc2f122e917ae4baac1156d6827c508cbbb09" diff --git a/pyproject.toml b/pyproject.toml index d88ff52..8184adb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -45,7 +45,7 @@ imagehash = "^4.3.1" pandas = "^2.2.1" comicfn2dict = "^0.2.4" tqdm = "^4.66.4" -darkseid = "^5.0.1" +darkseid = "^5.1.0" [tool.poetry.group.dev.dependencies] pre-commit = "^3.6.2"