Compare commits

...
8 Commits
Author SHA1 Message Date
hyugogirubato 0b21040b95 Release v3.3.3 2024-07-18 22:12:15 +02:00
hyugogirubato f52e112de9 Fixed saving pages in XML 2024-07-18 22:11:24 +02:00
hyugogirubato 2435ca396d Update .gitignore 2024-07-18 22:11:01 +02:00
hyugogirubato 5bc82581a3 Removed MD5 display 2024-07-18 22:10:51 +02:00
hyugogirubato 188b2e0164 New information fields in the XML 2024-07-18 22:10:26 +02:00
hyugogirubato 04b77d5ff9 Updated ComicInfo.xsd 2024-07-18 22:10:13 +02:00
hyugogirubato 3f777d30d6 Fix jpg format key 2024-07-18 20:58:42 +02:00
hyugogirubato 6847e7f281 Added pdf support 2024-07-18 00:11:23 +02:00
10 changed files with 86 additions and 29 deletions
+2 -1
View File
@@ -172,4 +172,5 @@ pyrightconfig.json
### CBZ ###
*.cbz
*.pdf
*.pdf
*.zip
+23
View File
@@ -4,6 +4,28 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [3.3.3] - 2024-07-18
### Added
- Reference links for XML schema.
- New information fields in the XML.
### Changed
- Removed MD5 display in the player (irrelevant).
- The displayed size in the player now reflects the total size of all images.
- Simplified the closing XML `Page` tag.
- Sorted `Page` keys in order.
- Updated `ComicInfo.xsd` defining the CBZ standard.
### Fixed
- Fixed the `.jpg` constant preventing the use of certain images.
- Fixed memory error related to the `pack()` method cache.
- Fixed saving pages in XML to comply with the standard.
- Added missing mandatory keys in the XML.
## [3.3.2] - 2024-07-18
### Added
@@ -125,6 +147,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
- Initial release.
[3.3.3]: https://github.com/hyugogirubato/cbz/releases/tag/v3.3.3
[3.3.2]: https://github.com/hyugogirubato/cbz/releases/tag/v3.3.2
[3.3.1]: https://github.com/hyugogirubato/cbz/releases/tag/v3.3.1
[3.3.0]: https://github.com/hyugogirubato/cbz/releases/tag/v3.3.0
+1 -1
View File
@@ -19,7 +19,7 @@ def main() -> None:
# Create ComicInfo object from CBZ file
try:
comic_info = ComicInfo.from_cbz(path=comic_path)
comic_info = ComicInfo.from_pdf(comic_path) if comic_path.suffix == '.pdf' else ComicInfo.from_cbz(comic_path)
# Launch the CBZ player
comic_info.show()
except Exception as e:
+20 -7
View File
@@ -1,11 +1,11 @@
from __future__ import annotations
import zipfile
from datetime import datetime
from enum import Enum
from io import BytesIO
from typing import Union
from functools import cache
from pathlib import Path
@@ -147,7 +147,7 @@ class ComicInfo(ComicModel):
if XML_NAME in names:
with zf.open(XML_NAME, 'r') as f:
comic_info = xmltodict.parse(f.read(), force_list=('Pages',)).get('ComicInfo', {})
comic_info = xmltodict.parse(f.read()).get('ComicInfo', {})
names.remove(XML_NAME)
comic = __info(
@@ -155,7 +155,7 @@ class ComicInfo(ComicModel):
fields=COMIC_FIELDS
)
pages_info = comic_info.get('Pages', [])
pages_info = comic_info.get('Pages', {}).get('Page', [])
for i, name in enumerate(names):
suffix = Path(name).suffix
if suffix:
@@ -201,16 +201,28 @@ class ComicInfo(ComicModel):
items={k: v for k, v in self.__dict__.items() if not k.startswith('_')},
fields=COMIC_FIELDS)
comic_pages = []
comic_info['Pages'] = []
for page in self.pages:
for i, page in enumerate(self.pages):
page_info = __info(
items={k: v for k, v in page.__dict__.items() if not k.startswith('_')},
fields=PAGE_FIELDS)
comic_info['Pages'].append(page_info)
page_info['@Image'] = i
comic_pages.append(dict(sorted(page_info.items())))
# https://github.com/anansi-project/rfcs/issues/3#issuecomment-671631676
utcnow = datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S.%f')[:-3] + ''
comic_info.update({
'@xmlns:xsd': 'http://www.w3.org/2001/XMLSchema',
'@xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance',
'FileSize': comic_info.get('FileSize', sum(p.image_size for p in self.pages)),
'FileCreationTime': comic_info.get('FileCreationTime', utcnow),
'FileModifiedTime': comic_info.get('FileModifiedTime', utcnow),
'PageCount': len(self.pages),
'Pages': {'Page': comic_pages}
})
return comic_info
@cache
def pack(self) -> bytes:
"""
Pack the comic information and pages into a CBZ file format.
@@ -220,9 +232,10 @@ class ComicInfo(ComicModel):
"""
zip_buffer = BytesIO()
with zipfile.ZipFile(zip_buffer, 'w', zipfile.ZIP_STORED) as zf:
content = xmltodict.unparse({'ComicInfo': self.get_info()}, pretty=True)
zf.writestr(
XML_NAME,
xmltodict.unparse({'ComicInfo': self.get_info()}, pretty=True).encode('utf-8')
content.replace('></Page>', ' />').encode('utf-8')
)
for i, page in enumerate(self.pages):
zf.writestr(f'page-{i + 1:03d}{page.suffix}', page.content)
+17 -9
View File
@@ -5,7 +5,7 @@ from langcodes import Language
XML_NAME = 'ComicInfo.xml'
IMAGE_FORMAT = {
'.jpeg', ' .jpg', # Joint Photographic Experts Group
'.jpeg', '.jpg', # Joint Photographic Experts Group
'.png', # Portable Network Graphics
'.gif', # Graphics Interchange Format
'.bmp', # Bitmap Image File
@@ -169,15 +169,23 @@ COMIC_FIELDS = {
'main_character_or_team': ('MainCharacterOrTeam', str),
'review': ('Review', str),
'language_iso': ('LanguageISO', LanguageISO),
'community_rating': ('CommunityRating', Rating)
'community_rating': ('CommunityRating', Rating),
'added': ('Added', str),
'released': ('Released', str),
'file_size': ('FileSize', int),
'file_modified_time': ('FileModifiedTime', str),
'file_creation_time': ('FileCreationTime', str),
'book_price': ('BookPrice', str),
'custom_values_store': ('CustomValuesStore', str)
}
PAGE_FIELDS = {
'type': ('Type', PageType),
'double': ('DoublePage', bool),
'key': ('Key', str),
'bookmark': ('Bookmark', str),
'image_size': ('ImageSize', int),
'image_width': ('ImageWidth', int),
'image_height': ('ImageHeight', int)
'image': ('@Image', int),
'type': ('@Type', PageType),
'double': ('@DoublePage', bool),
'key': ('@Key', str),
'bookmark': ('@Bookmark', str),
'image_size': ('@ImageSize', int),
'image_width': ('@ImageWidth', int),
'image_height': ('@ImageHeight', int)
}
+7
View File
@@ -102,6 +102,13 @@ class ComicModel(BaseModel):
review: str
language_iso: LanguageISO
community_rating: Rating
added: str
released: str
file_size: int
file_modified_time: str
file_creation_time: str
book_price: str
custom_values_store: str
def __init__(self, **kwargs):
"""
+5 -7
View File
@@ -1,4 +1,3 @@
import hashlib
import tkinter as tk
import os
@@ -235,17 +234,16 @@ class Player:
# Display summary for the first page
infos = self.comic_info.get_info()
packed = self.comic_info.pack()
infos['Pages'] = len(infos['Pages'])
infos['Size'] = readable_size(len(packed), decimal=2)
infos['MD5'] = hashlib.md5(packed).hexdigest()
self.summary_text.config(state=NORMAL)
self.summary_text.delete('1.0', tk.END)
for key, value in infos.items():
self.summary_text.insert(tk.END, f'{key}\n', 'bold')
self.summary_text.insert(tk.END, f'{value}\n\n', 'normal')
if not (key.startswith('@') or key == 'Pages'):
if key == 'FileSize':
value = readable_size(value)
self.summary_text.insert(tk.END, f'{key}\n', 'bold')
self.summary_text.insert(tk.END, f'{value}\n\n', 'normal')
self.summary_text.config(state=DISABLED)
self.summary_text.place(relwidth=1, relheight=1)
+7
View File
@@ -46,6 +46,13 @@
<xs:element minOccurs="0" maxOccurs="1" name="CommunityRating" type="Rating"/>
<xs:element minOccurs="0" maxOccurs="1" default="" name="MainCharacterOrTeam" type="xs:string"/>
<xs:element minOccurs="0" maxOccurs="1" default="" name="Review" type="xs:string"/>
<xs:element minOccurs="0" maxOccurs="1" default="" name="Added" type="xs:string"/>
<xs:element minOccurs="0" maxOccurs="1" default="" name="Released" type="xs:string"/>
<xs:element minOccurs="0" maxOccurs="1" default="" name="FileSize" type="xs:int"/>
<xs:element minOccurs="0" maxOccurs="1" default="" name="FileModifiedTime" type="xs:string"/>
<xs:element minOccurs="0" maxOccurs="1" default="" name="FileCreationTime" type="xs:string"/>
<xs:element minOccurs="0" maxOccurs="1" default="" name="BookPrice" type="xs:string"/>
<xs:element minOccurs="0" maxOccurs="1" default="" name="CustomValuesStore" type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:simpleType name="YesNo">
Generated
+3 -3
View File
@@ -333,13 +333,13 @@ reference = "localpypi"
[[package]]
name = "setuptools"
version = "71.0.0"
version = "71.0.3"
description = "Easily download, build, install, upgrade, and uninstall Python packages"
optional = false
python-versions = ">=3.8"
files = [
{file = "setuptools-71.0.0-py3-none-any.whl", hash = "sha256:f06fbe978a91819d250a30e0dc4ca79df713d909e24438a42d0ec300fc52247f"},
{file = "setuptools-71.0.0.tar.gz", hash = "sha256:98da3b8aca443b9848a209ae4165e2edede62633219afa493a58fbba57f72e2e"},
{file = "setuptools-71.0.3-py3-none-any.whl", hash = "sha256:f501b6e6db709818dc76882582d9c516bf3b67b948864c5fa1d1624c09a49207"},
{file = "setuptools-71.0.3.tar.gz", hash = "sha256:3d8531791a27056f4a38cd3e54084d8b1c4228ff9cf3f2d7dd075ec99f9fd70d"},
]
[package.extras]
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
[tool.poetry]
name = "cbz"
version = "3.3.2"
version = "3.3.3"
description = "CBZ simplifies creating, managing, and viewing comic book files in CBZ format, offering seamless packaging, metadata handling, and built-in viewing capabilities"
license = "MIT"
authors = ["hyugogirubato <65763543+hyugogirubato@users.noreply.github.com>"]