2023-02-13 19:15:27 +01:00
|
|
|
from pathlib import Path
|
2023-02-20 14:38:09 +01:00
|
|
|
from typing import Any, Dict, Tuple, Union
|
2023-02-13 19:15:27 +01:00
|
|
|
|
|
|
|
import xmltodict
|
|
|
|
from loguru import logger as log
|
|
|
|
|
2023-02-20 14:38:09 +01:00
|
|
|
from mangadlp.types import ComicInfo
|
|
|
|
|
2023-02-15 14:21:45 +01:00
|
|
|
METADATA_FILENAME = "ComicInfo.xml"
|
2023-02-15 13:50:59 +01:00
|
|
|
METADATA_TEMPLATE = Path("mangadlp/metadata/ComicInfo_v2.0.xml")
|
2023-02-15 14:21:45 +01:00
|
|
|
# define metadata types, defaults and valid values. an empty list means no value check
|
|
|
|
# {key: (type, default value, valid values)}
|
2023-02-18 16:21:03 +01:00
|
|
|
METADATA_TYPES: Dict[str, Tuple[type, Any, list[Union[str, int]]]] = {
|
2023-02-15 13:50:59 +01:00
|
|
|
"Title": (str, None, []),
|
|
|
|
"Series": (str, None, []),
|
|
|
|
"Number": (str, None, []),
|
|
|
|
"Count": (int, None, []),
|
|
|
|
"Volume": (int, None, []),
|
|
|
|
"AlternateSeries": (str, None, []),
|
|
|
|
"AlternateNumber": (str, None, []),
|
|
|
|
"AlternateCount": (int, None, []),
|
|
|
|
"Summary": (str, None, []),
|
|
|
|
"Notes": (str, "Downloaded with https://github.com/olofvndrhr/manga-dlp", []),
|
|
|
|
"Year": (int, None, []),
|
|
|
|
"Month": (int, None, []),
|
|
|
|
"Day": (int, None, []),
|
|
|
|
"Writer": (str, None, []),
|
|
|
|
"Colorist": (str, None, []),
|
|
|
|
"Publisher": (str, None, []),
|
|
|
|
"Genre": (str, None, []),
|
|
|
|
"Web": (str, None, []),
|
|
|
|
"PageCount": (int, None, []),
|
|
|
|
"LanguageISO": (str, None, []),
|
|
|
|
"Format": (str, None, []),
|
|
|
|
"BlackAndWhite": (str, None, ["Yes", "No", "Unknown"]),
|
|
|
|
"Manga": (str, "Yes", ["Yes", "No", "Unknown", "YesAndRightToLeft"]),
|
|
|
|
"ScanInformation": (str, None, []),
|
|
|
|
"SeriesGroup": (str, None, []),
|
|
|
|
"AgeRating": (
|
|
|
|
str,
|
|
|
|
None,
|
|
|
|
[
|
|
|
|
"Unknown",
|
|
|
|
"Adults Only 18+",
|
|
|
|
"Early Childhood",
|
|
|
|
"Everyone",
|
|
|
|
"Everyone 10+",
|
|
|
|
"G",
|
|
|
|
"Kids to Adults",
|
|
|
|
"M",
|
|
|
|
"MA15+",
|
|
|
|
"Mature 17+",
|
|
|
|
"PG",
|
|
|
|
"R18+",
|
|
|
|
"Rating Pending",
|
|
|
|
"Teen",
|
|
|
|
"X18+",
|
|
|
|
],
|
|
|
|
),
|
|
|
|
"CommunityRating": (int, None, [1, 2, 3, 4, 5]),
|
|
|
|
}
|
2023-02-13 19:15:27 +01:00
|
|
|
|
2023-02-13 23:17:52 +01:00
|
|
|
|
2023-02-20 14:03:40 +01:00
|
|
|
def validate_metadata(metadata_in: ComicInfo) -> Dict[str, ComicInfo]:
|
2023-02-15 13:50:59 +01:00
|
|
|
log.info("Validating metadata")
|
2023-02-13 19:15:27 +01:00
|
|
|
|
2023-02-20 14:03:40 +01:00
|
|
|
metadata_valid: dict[str, ComicInfo] = {"ComicInfo": {}}
|
2023-02-15 13:50:59 +01:00
|
|
|
for key, value in METADATA_TYPES.items():
|
|
|
|
metadata_type, metadata_default, metadata_validation = value
|
|
|
|
|
|
|
|
# add default value if present
|
|
|
|
if metadata_default:
|
2023-02-15 16:47:43 +01:00
|
|
|
log.debug(
|
|
|
|
f"Setting default value for Key:{key} -> value={metadata_default}"
|
|
|
|
)
|
2023-02-15 13:50:59 +01:00
|
|
|
metadata_valid["ComicInfo"][key] = metadata_default
|
|
|
|
|
|
|
|
# check if metadata key is available
|
2023-02-13 19:15:27 +01:00
|
|
|
try:
|
2023-02-20 14:03:40 +01:00
|
|
|
md_to_check: Union[str, int, None] = metadata_in[key]
|
2023-02-13 19:15:27 +01:00
|
|
|
except KeyError:
|
|
|
|
continue
|
2023-02-15 13:50:59 +01:00
|
|
|
# check if provided metadata item is empty
|
|
|
|
if not md_to_check:
|
|
|
|
continue
|
|
|
|
|
2023-02-14 13:31:55 +01:00
|
|
|
# check if metadata type is correct
|
2023-02-15 13:50:59 +01:00
|
|
|
log.debug(f"Key:{key} -> value={type(md_to_check)} -> check={metadata_type}")
|
2023-02-18 12:29:25 +01:00
|
|
|
if not isinstance(md_to_check, metadata_type):
|
2023-02-15 13:50:59 +01:00
|
|
|
log.warning(
|
|
|
|
f"Metadata has wrong type: {key}:{metadata_type} -> {md_to_check}"
|
|
|
|
)
|
|
|
|
continue
|
|
|
|
|
|
|
|
# check if metadata is valid
|
|
|
|
log.debug(f"Key:{key} -> value={md_to_check} -> valid={metadata_validation}")
|
|
|
|
if (len(metadata_validation) > 0) and (md_to_check not in metadata_validation):
|
2023-02-14 13:31:55 +01:00
|
|
|
log.warning(
|
2023-02-15 13:50:59 +01:00
|
|
|
f"Metadata is invalid: {key}:{metadata_validation} -> {md_to_check}"
|
2023-02-14 13:31:55 +01:00
|
|
|
)
|
|
|
|
continue
|
|
|
|
|
2023-02-15 13:50:59 +01:00
|
|
|
log.debug(f"Updating metadata: '{key}' = '{md_to_check}'")
|
|
|
|
metadata_valid["ComicInfo"][key] = md_to_check
|
|
|
|
|
|
|
|
return metadata_valid
|
|
|
|
|
|
|
|
|
2023-02-20 14:03:40 +01:00
|
|
|
def write_metadata(chapter_path: Path, metadata: ComicInfo) -> None:
|
|
|
|
if metadata["Format"] == "pdf": # pyright:ignore
|
2023-02-15 13:50:59 +01:00
|
|
|
log.warning("Can't add metadata for pdf format. Skipping")
|
|
|
|
return
|
|
|
|
|
2023-02-15 14:21:45 +01:00
|
|
|
metadata_file = chapter_path / METADATA_FILENAME
|
2023-02-13 19:15:27 +01:00
|
|
|
|
2023-02-15 13:50:59 +01:00
|
|
|
log.debug(f"Metadata items: {metadata}")
|
|
|
|
metadata_valid = validate_metadata(metadata)
|
|
|
|
|
|
|
|
log.info(f"Writing metadata to: '{metadata_file}'")
|
|
|
|
metadata_export = xmltodict.unparse(
|
|
|
|
metadata_valid, pretty=True, indent=" " * 4, short_empty_elements=True
|
|
|
|
)
|
2023-02-13 23:17:52 +01:00
|
|
|
metadata_file.touch(exist_ok=True)
|
2023-02-13 19:15:27 +01:00
|
|
|
metadata_file.write_text(metadata_export, encoding="utf8")
|