Comic
MetadataFormat
Bases: Enum
An enumeration of supported metadata formats for comic books.
This enum defines the different metadata formats that can be stored within comic book archives. Each format has specific characteristics and use cases.
| ATTRIBUTE | DESCRIPTION |
|---|---|
METRON_INFO |
MetronInfo format - A comprehensive metadata format that includes detailed bibliographic information and is designed for library and collection management systems.
|
COMIC_INFO |
ComicInfo format - The standard metadata format used by ComicRack and other comic reading applications.
|
UNKNOWN |
Unknown or unsupported metadata format.
|
Examples:
>>> fmt = MetadataFormat.COMIC_INFO
>>> print(fmt) # Output: ComicInfo
>>> comic = Comic(Path("example.cbz"))
>>> comic.has_metadata(MetadataFormat.METRON_INFO)
Functions
__str__() -> str
Return a human-readable string representation of the metadata format.
| RETURNS | DESCRIPTION |
|---|---|
str
|
A capitalized string representation (e.g., "ComicInfo", "MetronInfo").
TYPE:
|
Examples:
>>> str(MetadataFormat.COMIC_INFO)
'ComicInfo'
ComicError
Bases: Exception
Base exception for all comic-related errors.
This is the parent class for all exceptions raised by the Comic class and related functionality. Use this for general exception handling.
ComicArchiveError
Bases: ComicError
Exception raised when there are issues with the comic archive file.
This exception is raised when:
- The comic file doesn't exist
- The archive is corrupted or unreadable
- Archive format is not supported
- File system permissions prevent access
ComicMetadataError
Bases: ComicError
Exception raised when there are issues with comic metadata operations.
This exception is raised when:
- Metadata format is not supported
- Metadata parsing fails
- Metadata validation errors occur
Comic(path: Path | str)
A comprehensive comic book archive handler with metadata support.
The Comic class provides a high-level interface for working with comic book archives in CBZ (ZIP) CBR (RAR), CBT (TAR) and CB7 (7ZIP) formats. It supports reading and writing metadata in ComicInfo and MetronInfo formats, page manipulation, and archive validation.
Key Features
- Support for CBZ/ZIP, CBR/RAR, CBT/TAR, and CB7/7ZIP (optional) comic archives
- Read/write ComicInfo and MetronInfo metadata
- Page extraction and manipulation
- Archive validation and format detection
- Metadata validation with schema version detection
- Export capabilities (e.g., CBR to CBZ conversion / CBT to CBZ conversion)
Thread Safety
This class is not thread-safe. Each thread should use its own Comic instance.
Performance Considerations
- Page lists and metadata are cached after first access
- Large archives may consume significant memory when processing all pages
- RAR archives are read-only due to library limitations
Examples:
Basic usage:
>>> from pathlib import Path
>>> comic = Comic(Path("my_comic.cbz"))
>>>
>>> # Check if it's a valid comic
>>> if comic.is_valid_comic():
... print(f"Comic '{comic.name}' has {comic.get_number_of_pages()} pages")
>>>
>>> # Read metadata
>>> if comic.has_metadata(MetadataFormat.COMIC_INFO):
... metadata = comic.read_metadata(MetadataFormat.COMIC_INFO)
... print(f"Series: {metadata.series.name}")
>>>
>>> # Get a page
>>> page_data = comic.get_page(0) # First page
>>> if page_data:
... with open("cover.jpg", "wb") as f:
... f.write(page_data)
| ATTRIBUTE | DESCRIPTION |
|---|---|
path |
The file system path to the comic archive.
TYPE:
|
name |
The filename of the comic archive.
TYPE:
|
size |
The size of the comic archive in bytes.
TYPE:
|
Initialize a Comic object with the provided path.
| PARAMETER | DESCRIPTION |
|---|---|
path
|
The file system path to the comic archive. Can be a string or Path object. The file must exist and be a valid ZIP or RAR archive.
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
ComicArchiveError
|
If the path doesn't exist, isn't accessible, or can't be opened as a valid archive format. |
Examples:
>>> comic = Comic("my_comic.cbz")
>>> comic_ = Comic(Path("/path/to/comic.cbr"))
>>> print(comic.name)
>>> print(comic_.name)
Attributes
name: str
property
Get the filename of the comic archive.
| RETURNS | DESCRIPTION |
|---|---|
str
|
The filename without the directory path.
TYPE:
|
path: Path
property
Get the file system path of the comic archive.
| RETURNS | DESCRIPTION |
|---|---|
Path
|
The path to the comic archive file.
TYPE:
|
size: int
property
Get the size of the comic archive file in bytes.
| RETURNS | DESCRIPTION |
|---|---|
int
|
The file size in bytes.
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
OSError
|
If the file cannot be accessed or doesn't exist. |
Functions
__eq__(other: object) -> bool
Check if two Comic objects are equal based on their file paths.
| PARAMETER | DESCRIPTION |
|---|---|
other
|
Another object to compare with.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
bool
|
True if both objects are Comic instances with the same path.
TYPE:
|
__hash__() -> int
Make Comic objects hashable based on their file path.
| RETURNS | DESCRIPTION |
|---|---|
int
|
Hash value based on the file path.
TYPE:
|
Note
This allows Comic objects to be used in sets and as dictionary keys.
__repr__() -> str
Return a detailed string representation of the Comic object.
| RETURNS | DESCRIPTION |
|---|---|
str
|
A string representation showing the path and page count.
TYPE:
|
Examples:
>>> comic = Comic(Path("example.cbz"))
>>> repr(comic)
"Comic(path=PosixPath('/comics/example.cbz'), pages=24)"
__str__() -> str
Return the name of the comic file.
| RETURNS | DESCRIPTION |
|---|---|
str
|
The filename of the comic archive.
TYPE:
|
export_as_zip(zip_filename: Path) -> bool
Export the comic archive to CBZ (ZIP) format.
Converts RAR/CBR, CBT, or CB7 archives to ZIP/CBZ format. Returns True immediately if already ZIP. Preserves all pages, metadata, and directory structure.
| PARAMETER | DESCRIPTION |
|---|---|
zip_filename
|
Path where the ZIP archive will be created (overwrites if exists).
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
bool
|
True if successful or already ZIP, False if failed.
TYPE:
|
Note
Large archives may require significant time and disk space for conversion.
get_metadata_formats() -> set[MetadataFormat]
Return the set of metadata formats present in the archive.
| RETURNS | DESCRIPTION |
|---|---|
set[MetadataFormat]
|
A set of MetadataFormat enums representing the available metadata. |
get_number_of_pages() -> int
Get the total number of pages (images) in the archive.
| RETURNS | DESCRIPTION |
|---|---|
int
|
The number of image files in the archive.
TYPE:
|
Note
This count includes only supported image formats and excludes hidden files. The result is cached for performance.
get_page(index: int) -> bytes | None
Retrieve the raw image data for a specific page.
| PARAMETER | DESCRIPTION |
|---|---|
index
|
The 0-based index of the page to retrieve.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
bytes | None
|
bytes | None: The raw image data of the page, or None if the page cannot be retrieved (invalid index or read error). |
Examples:
>>> comic = Comic(Path("example.cbz"))
>>> page_data = comic.get_page(0) # Get first page
>>> if page_data:
... with open("page_1.jpg", "wb") as f:
... f.write(page_data)
Note
The returned data is the raw image file content and can be written directly to a file or processed with image libraries like PIL.
get_page_name(index: int) -> str | None
Get the filename of a page by its index.
| PARAMETER | DESCRIPTION |
|---|---|
index
|
The 0-based index of the page.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
str | None
|
str | None: The filename of the page within the archive, or None if the index is invalid or out of range. |
Examples:
>>> comic = Comic(Path("example.cbz"))
>>> filename = comic.get_page_name(0)
>>> print(filename) # Output: "page_01.jpg"
get_page_name_list(sort_list: bool = True) -> list[str]
Get a list of all page filenames in the archive.
| PARAMETER | DESCRIPTION |
|---|---|
sort_list
|
Whether to sort the list using natural sorting. Default is True.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
list[str]
|
list[str]: A list of page filenames, filtered to include only image files. |
Note
- Only image files are included in the list
- Hidden files (starting with '.') are excluded
- Natural sorting ensures proper ordering (e.g., page10.jpg comes after page2.jpg)
- Results are cached for performance
has_metadata(fmt: MetadataFormat) -> bool
Check if the archive contains metadata in the specified format.
Performs case-insensitive search for metadata files. Results are cached.
| PARAMETER | DESCRIPTION |
|---|---|
fmt
|
Metadata format to check (COMIC_INFO or METRON_INFO).
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
bool
|
True if metadata exists, False otherwise.
TYPE:
|
is_archive_valid() -> bool
Test whether the archive file is valid and readable.
This method performs a comprehensive check to determine if the archive can be opened and read as either a ZIP or RAR file.
| RETURNS | DESCRIPTION |
|---|---|
bool
|
True if the archive is valid and readable, False otherwise.
TYPE:
|
Note
This method is more thorough than just checking file extensions, as it actually attempts to open and validate the archive structure.
is_image(name_path: Path) -> bool
staticmethod
Check if a file is a supported image format.
| PARAMETER | DESCRIPTION |
|---|---|
name_path
|
The path to check (can be filename or full path).
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
bool
|
True if the file has a supported image extension and isn't a hidden file (doesn't start with '.').
TYPE:
|
Note
Supported formats: .jpg, .jpeg, .png, .gif, .webp Hidden files (starting with '.') are excluded.
is_valid_comic() -> bool
Perform comprehensive validation of the comic archive.
Checks file existence, archive validity, and comic content (at least one image).
| RETURNS | DESCRIPTION |
|---|---|
bool
|
True if valid comic archive, False otherwise.
TYPE:
|
is_writable() -> bool
Check if the archive supports write operations.
| RETURNS | DESCRIPTION |
|---|---|
bool
|
True if the archive can be modified, False otherwise.
TYPE:
|
Note
RAR archives are typically read-only due to library limitations. ZIP archives can be written to if the file system permissions allow it.
read_metadata(metadata_format: MetadataFormat) -> Metadata
Read metadata from the archive in the specified format.
| PARAMETER | DESCRIPTION |
|---|---|
metadata_format
|
The format of metadata to read (COMIC_INFO or METRON_INFO).
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
Metadata
|
The parsed metadata object, or an empty Metadata instance if the format is not recognized or parsing fails.
TYPE:
|
Examples:
>>> comic = Comic(Path("example.cbz"))
>>> if comic.has_metadata(MetadataFormat.COMIC_INFO):
... metadata = comic.read_metadata(MetadataFormat.COMIC_INFO)
... print(f"Series: {metadata.series.name}")
... print(f"Issue: {metadata.issue}")
Note
- The result is cached after first read
- Page list validation is performed to ensure consistency
- Returns empty Metadata object if format is unsupported
read_raw_ci_metadata() -> str | None
Read raw ComicInfo metadata XML from the archive.
| RETURNS | DESCRIPTION |
|---|---|
str | None
|
str | None: The raw ComicInfo XML as a string, or None if not found. |
Note
This method returns the raw XML content without any parsing or validation. Use read_metadata() for parsed metadata objects.
read_raw_mi_metadata() -> str | None
Read raw MetronInfo metadata XML from the archive.
| RETURNS | DESCRIPTION |
|---|---|
str | None
|
str | None: The raw MetronInfo XML as a string, or None if not found. |
Note
This method returns the raw XML content without any parsing or validation. Use read_metadata() for parsed metadata objects.
remove_metadata(metadata_format_list: list[MetadataFormat]) -> bool
Remove metadata from the comic archive.
| PARAMETER | DESCRIPTION |
|---|---|
metadata_format_list
|
A list of metadata formats to remove.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
bool
|
True if any metadata was successfully removed or didn't exist, False if an error occurred.
TYPE:
|
Examples:
>>> comic = Comic(Path("example.cbz"))
>>> success = comic.remove_metadata([MetadataFormat.COMIC_INFO])
>>> if success:
... print("ComicInfo metadata removed")
Note
- If the metadata doesn't exist, this method returns True
- The archive must be writable
- All metadata files matching the format are removed (case-insensitive)
remove_pages(pages_index: list[int]) -> bool
Remove pages from the comic archive by their indices (0-based).
This is a destructive operation that cannot be undone. Metadata caches are invalidated after successful removal.
| PARAMETER | DESCRIPTION |
|---|---|
pages_index
|
List of zero-based page indices to remove.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
bool
|
True if successful, False if failed.
TYPE:
|
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
If any page index is negative or out of range. |
seems_to_be_a_comic_archive() -> bool
Determine if the file appears to be a comic book archive.
A file is considered a comic archive if it meets the following criteria:
- It's a supported archive based on it's extension
- It contains at least one image file
| RETURNS | DESCRIPTION |
|---|---|
bool
|
True if the file appears to be a comic archive, False otherwise.
TYPE:
|
Note
This is a heuristic check and may not catch all edge cases. Use is_valid_comic() for a more comprehensive validation.
validate_metadata(metadata_format: MetadataFormat) -> SchemaVersion
Validate metadata XML and return its schema version.
| PARAMETER | DESCRIPTION |
|---|---|
metadata_format
|
Format to validate (COMIC_INFO or METRON_INFO).
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
SchemaVersion
|
Detected schema version, or SchemaVersion.Unknown if invalid/not found.
TYPE:
|
write_metadata(metadata: Metadata, metadata_format: MetadataFormat) -> bool
Write metadata to the comic archive in the specified format.
| PARAMETER | DESCRIPTION |
|---|---|
metadata
|
Metadata object to write.
TYPE:
|
metadata_format
|
Format to use: - COMIC_INFO: ComicRack reader standard format - METRON_INFO: A new comic book metadata format
TYPE:
|
Returns: bool: True if successful, False if failed (read-only archive, I/O errors).
| RAISES | DESCRIPTION |
|---|---|
ComicMetadataError
|
If metadata format is not supported. |
Note
ComicInfo writes include page size calculations (slower for large archives). MetronInfo writes skip page calculations (faster).
Examples:
>>> comic = Comic("example.cbz")
>>> metadata = Metadata()
>>> metadata.series = "Amazing Spider-Man"
>>> comic.write_metadata(metadata, MetadataFormat.COMIC_INFO)