Add OverlayMode options for read style and data source
This commit is contained in:
parent
851339d4e3
commit
8b0683f67c
@ -24,6 +24,7 @@ from __future__ import annotations
|
||||
import copy
|
||||
import dataclasses
|
||||
import logging
|
||||
import sys
|
||||
from collections.abc import Sequence
|
||||
from enum import Enum, auto
|
||||
from typing import TYPE_CHECKING, Any, TypedDict, Union
|
||||
@ -32,6 +33,7 @@ from typing_extensions import NamedTuple, Required
|
||||
|
||||
from comicapi import utils
|
||||
from comicapi._url import Url, parse_url
|
||||
from comicapi.utils import norm_fold
|
||||
|
||||
if TYPE_CHECKING:
|
||||
Union
|
||||
@ -46,6 +48,45 @@ class __remove(Enum):
|
||||
REMOVE = __remove.REMOVE
|
||||
|
||||
|
||||
if sys.version_info < (3, 11):
|
||||
|
||||
class StrEnum(str, Enum):
|
||||
"""
|
||||
Enum where members are also (and must be) strings
|
||||
"""
|
||||
|
||||
def __new__(cls, *values: Any) -> Any:
|
||||
"values must already be of type `str`"
|
||||
if len(values) > 3:
|
||||
raise TypeError(f"too many arguments for str(): {values!r}")
|
||||
if len(values) == 1:
|
||||
# it must be a string
|
||||
if not isinstance(values[0], str):
|
||||
raise TypeError(f"{values[0]!r} is not a string")
|
||||
if len(values) >= 2:
|
||||
# check that encoding argument is a string
|
||||
if not isinstance(values[1], str):
|
||||
raise TypeError(f"encoding must be a string, not {values[1]!r}")
|
||||
if len(values) == 3:
|
||||
# check that errors argument is a string
|
||||
if not isinstance(values[2], str):
|
||||
raise TypeError("errors must be a string, not %r" % (values[2]))
|
||||
value = str(*values)
|
||||
member = str.__new__(cls, value)
|
||||
member._value_ = value
|
||||
return member
|
||||
|
||||
@staticmethod
|
||||
def _generate_next_value_(name: str, start: int, count: int, last_values: Any) -> str:
|
||||
"""
|
||||
Return the lower-cased version of the member name.
|
||||
"""
|
||||
return name.lower()
|
||||
|
||||
else:
|
||||
from enum import StrEnum
|
||||
|
||||
|
||||
class PageType:
|
||||
"""
|
||||
These page info classes are exactly the same as the CIX scheme, since
|
||||
@ -104,6 +145,12 @@ class TagOrigin(NamedTuple):
|
||||
name: str
|
||||
|
||||
|
||||
class OverlayMode(StrEnum):
|
||||
overlay = auto()
|
||||
add_missing = auto()
|
||||
combine = auto()
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class GenericMetadata:
|
||||
writer_synonyms = ("writer", "plotter", "scripter", "script")
|
||||
@ -214,101 +261,172 @@ class GenericMetadata:
|
||||
new_md.__post_init__()
|
||||
return new_md
|
||||
|
||||
def overlay(self, new_md: GenericMetadata) -> None:
|
||||
"""Overlay a metadata object on this one
|
||||
def credit_dedupe(self, cur: list[Credit], new: list[Credit]) -> list[Credit]:
|
||||
if len(new) == 0:
|
||||
return cur
|
||||
if len(cur) == 0:
|
||||
return new
|
||||
|
||||
That is, when the new object has non-None values, over-write them
|
||||
to this one.
|
||||
"""
|
||||
# Create dict for deduplication
|
||||
new_dict: dict[str, Credit] = {f"{norm_fold(n['person'])}_{n['role'].casefold()}": n for n in new}
|
||||
cur_dict: dict[str, Credit] = {f"{norm_fold(c['person'])}_{c['role'].casefold()}": c for c in cur}
|
||||
|
||||
def assign(cur: str, new: Any) -> None:
|
||||
if new is not None:
|
||||
if new is REMOVE:
|
||||
if isinstance(getattr(self, cur), (list, set)):
|
||||
getattr(self, cur).clear()
|
||||
else:
|
||||
setattr(self, cur, None)
|
||||
return
|
||||
# Any duplicates use the 'new' value
|
||||
cur_dict.update(new_dict)
|
||||
return list(cur_dict.values())
|
||||
|
||||
if isinstance(new, str) and len(new) == 0:
|
||||
setattr(self, cur, None)
|
||||
elif isinstance(new, (list, set)) and len(new) == 0:
|
||||
pass
|
||||
def assign_dedupe(self, new: list[str] | set[str], cur: list[str] | set[str]) -> list[str] | set[str]:
|
||||
"""Dedupes normalised (NFKD), casefolded values using 'new' values on collisions"""
|
||||
if len(new) == 0:
|
||||
return cur
|
||||
if len(cur) == 0:
|
||||
return new
|
||||
|
||||
# Create dict values for deduplication
|
||||
new_dict: dict[str, str] = {norm_fold(n): n for n in new}
|
||||
cur_dict: dict[str, str] = {norm_fold(c): c for c in cur}
|
||||
|
||||
if isinstance(cur, list):
|
||||
cur_dict.update(new_dict)
|
||||
return list(cur_dict.values())
|
||||
|
||||
if isinstance(cur, set):
|
||||
cur_dict.update(new_dict)
|
||||
return set(cur_dict.values())
|
||||
|
||||
# All else fails
|
||||
return cur
|
||||
|
||||
def assign_overlay(self, cur: Any, new: Any) -> Any:
|
||||
"""Overlay - When the 'new' object has non-None values, overwrite 'cur'(rent) with 'new'."""
|
||||
if new is None:
|
||||
return cur
|
||||
if isinstance(new, (list, set)) and len(new) == 0:
|
||||
return cur
|
||||
else:
|
||||
return new
|
||||
|
||||
def assign_add_missing(self, cur: Any, new: Any) -> Any:
|
||||
"""Add Missing - Any 'cur(rent)' values that are None or an empty list/set, add 'new' non-None values"""
|
||||
if new is None:
|
||||
return cur
|
||||
if cur is None:
|
||||
return new
|
||||
elif isinstance(cur, (list, set)) and len(cur) == 0:
|
||||
return new
|
||||
else:
|
||||
return cur
|
||||
|
||||
def assign_combine(self, cur: Any, new: Any) -> Any:
|
||||
"""Combine - Combine lists and sets (checking for dupes). All non-None values from new replace cur(rent)"""
|
||||
if new is None:
|
||||
return cur
|
||||
if isinstance(new, (list, set)) and isinstance(cur, (list, set)):
|
||||
# Check for weblinks (Url is a tuple)
|
||||
if len(new) > 0 and isinstance(new, list) and isinstance(new[0], Url):
|
||||
return list(set(new).union(cur))
|
||||
return self.assign_dedupe(new, cur)
|
||||
else:
|
||||
return new
|
||||
|
||||
def overlay(self, new_md: GenericMetadata, mode: OverlayMode = OverlayMode.overlay) -> None:
|
||||
"""Overlay a new metadata object on this one"""
|
||||
|
||||
assign_funcs = {
|
||||
OverlayMode.overlay: self.assign_overlay,
|
||||
OverlayMode.add_missing: self.assign_add_missing,
|
||||
OverlayMode.combine: self.assign_combine,
|
||||
}
|
||||
|
||||
def assign(cur: Any, new: Any) -> Any:
|
||||
if new is REMOVE:
|
||||
if isinstance(cur, (list, set)):
|
||||
cur.clear()
|
||||
return cur
|
||||
else:
|
||||
setattr(self, cur, new)
|
||||
return None
|
||||
|
||||
assign_func = assign_funcs.get(mode, self.assign_overlay)
|
||||
return assign_func(cur, new)
|
||||
|
||||
if not new_md.is_empty:
|
||||
self.is_empty = False
|
||||
|
||||
assign("tag_origin", new_md.tag_origin)
|
||||
assign("issue_id", new_md.issue_id)
|
||||
assign("series_id", new_md.series_id)
|
||||
self.tag_origin = assign(self.tag_origin, new_md.tag_origin) # TODO use and purpose now?
|
||||
self.issue_id = assign(self.issue_id, new_md.issue_id)
|
||||
self.series_id = assign(self.series_id, new_md.series_id)
|
||||
|
||||
assign("series", new_md.series)
|
||||
assign("series_aliases", new_md.series_aliases)
|
||||
assign("issue", new_md.issue)
|
||||
assign("issue_count", new_md.issue_count)
|
||||
assign("title", new_md.title)
|
||||
assign("title_aliases", new_md.title_aliases)
|
||||
assign("volume", new_md.volume)
|
||||
assign("volume_count", new_md.volume_count)
|
||||
assign("genres", new_md.genres)
|
||||
assign("description", new_md.description)
|
||||
assign("notes", new_md.notes)
|
||||
self.series = assign(self.series, new_md.series)
|
||||
self.series_aliases = assign(self.series_aliases, new_md.series_aliases)
|
||||
self.issue = assign(self.issue, new_md.issue)
|
||||
self.issue_count = assign(self.issue_count, new_md.issue_count)
|
||||
self.title = assign(self.title, new_md.title)
|
||||
self.title_aliases = assign(self.title_aliases, new_md.title_aliases)
|
||||
self.volume = assign(self.volume, new_md.volume)
|
||||
self.volume_count = assign(self.volume_count, new_md.volume_count)
|
||||
self.genres = assign(self.genres, new_md.genres)
|
||||
self.description = assign(self.description, new_md.description)
|
||||
self.notes = assign(self.notes, new_md.notes)
|
||||
|
||||
assign("alternate_series", new_md.alternate_series)
|
||||
assign("alternate_number", new_md.alternate_number)
|
||||
assign("alternate_count", new_md.alternate_count)
|
||||
assign("story_arcs", new_md.story_arcs)
|
||||
assign("series_groups", new_md.series_groups)
|
||||
self.alternate_series = assign(self.alternate_series, new_md.alternate_series)
|
||||
self.alternate_number = assign(self.alternate_number, new_md.alternate_number)
|
||||
self.alternate_count = assign(self.alternate_count, new_md.alternate_count)
|
||||
self.story_arcs = assign(self.story_arcs, new_md.story_arcs)
|
||||
self.series_groups = assign(self.series_groups, new_md.series_groups)
|
||||
|
||||
assign("publisher", new_md.publisher)
|
||||
assign("imprint", new_md.imprint)
|
||||
assign("day", new_md.day)
|
||||
assign("month", new_md.month)
|
||||
assign("year", new_md.year)
|
||||
assign("language", new_md.language)
|
||||
assign("country", new_md.country)
|
||||
assign("web_links", new_md.web_links)
|
||||
assign("format", new_md.format)
|
||||
assign("manga", new_md.manga)
|
||||
assign("black_and_white", new_md.black_and_white)
|
||||
assign("maturity_rating", new_md.maturity_rating)
|
||||
assign("critical_rating", new_md.critical_rating)
|
||||
assign("scan_info", new_md.scan_info)
|
||||
self.publisher = assign(self.publisher, new_md.publisher)
|
||||
self.imprint = assign(self.imprint, new_md.imprint)
|
||||
self.day = assign(self.day, new_md.day)
|
||||
self.month = assign(self.month, new_md.month)
|
||||
self.year = assign(self.year, new_md.year)
|
||||
self.language = assign(self.language, new_md.language)
|
||||
self.country = assign(self.country, new_md.country)
|
||||
self.web_links = assign(self.web_links, new_md.web_links)
|
||||
self.format = assign(self.format, new_md.format)
|
||||
self.manga = assign(self.manga, new_md.manga)
|
||||
self.black_and_white = assign(self.black_and_white, new_md.black_and_white)
|
||||
self.maturity_rating = assign(self.maturity_rating, new_md.maturity_rating)
|
||||
self.critical_rating = assign(self.critical_rating, new_md.critical_rating)
|
||||
self.scan_info = assign(self.scan_info, new_md.scan_info)
|
||||
|
||||
assign("tags", new_md.tags)
|
||||
assign("pages", new_md.pages)
|
||||
assign("page_count", new_md.page_count)
|
||||
self.tags = assign(self.tags, new_md.tags)
|
||||
self.pages = assign(self.pages, new_md.pages)
|
||||
self.page_count = assign(self.page_count, new_md.page_count)
|
||||
|
||||
assign("characters", new_md.characters)
|
||||
assign("teams", new_md.teams)
|
||||
assign("locations", new_md.locations)
|
||||
self.overlay_credits(new_md.credits)
|
||||
self.characters = assign(self.characters, new_md.characters)
|
||||
self.teams = assign(self.teams, new_md.teams)
|
||||
self.locations = assign(self.locations, new_md.locations)
|
||||
self.credits = self.assign_credits(self.credits, new_md.credits)
|
||||
|
||||
assign("price", new_md.price)
|
||||
assign("is_version_of", new_md.is_version_of)
|
||||
assign("rights", new_md.rights)
|
||||
assign("identifier", new_md.identifier)
|
||||
assign("last_mark", new_md.last_mark)
|
||||
assign("_cover_image", new_md._cover_image)
|
||||
assign("_alternate_images", new_md._alternate_images)
|
||||
self.price = assign(self.price, new_md.price)
|
||||
self.is_version_of = assign(self.is_version_of, new_md.is_version_of)
|
||||
self.rights = assign(self.rights, new_md.rights)
|
||||
self.identifier = assign(self.identifier, new_md.identifier)
|
||||
self.last_mark = assign(self.last_mark, new_md.last_mark)
|
||||
self._cover_image = assign(self._cover_image, new_md._cover_image)
|
||||
self._alternate_images = assign(self._alternate_images, new_md._alternate_images)
|
||||
|
||||
def overlay_credits(self, new_credits: list[Credit]) -> None:
|
||||
def assign_credits_overlay(self, cur_credits: list[Credit], new_credits: list[Credit]) -> list[Credit]:
|
||||
return self.credit_dedupe(cur_credits, new_credits)
|
||||
|
||||
def assign_credits_add_missing(self, cur_credits: list[Credit], new_credits: list[Credit]) -> list[Credit]:
|
||||
# Send new_credits as cur_credits and vis-versa to keep cur_credit on duplication
|
||||
return self.credit_dedupe(new_credits, cur_credits)
|
||||
|
||||
def assign_credits(
|
||||
self, cur_credits: list[Credit], new_credits: list[Credit], mode: OverlayMode = OverlayMode.overlay
|
||||
) -> list[Credit]:
|
||||
if new_credits is REMOVE:
|
||||
self.credits = []
|
||||
return
|
||||
for c in new_credits:
|
||||
primary = bool("primary" in c and c["primary"])
|
||||
return []
|
||||
|
||||
# Remove credit role if person is blank
|
||||
if c["person"] == "":
|
||||
for r in reversed(self.credits):
|
||||
if r["role"].casefold() == c["role"].casefold():
|
||||
self.credits.remove(r)
|
||||
# otherwise, add it!
|
||||
else:
|
||||
self.add_credit(c["person"], c["role"], primary)
|
||||
assign_credit_funcs = {
|
||||
OverlayMode.overlay: self.assign_credits_overlay,
|
||||
OverlayMode.add_missing: self.assign_credits_add_missing,
|
||||
OverlayMode.combine: self.assign_credits_overlay,
|
||||
}
|
||||
|
||||
assign_credit_func = assign_credit_funcs.get(mode, self.assign_credits_overlay)
|
||||
return assign_credit_func(cur_credits, new_credits)
|
||||
|
||||
def apply_default_page_list(self, page_list: Sequence[str]) -> None:
|
||||
# generate a default page list, with the first page marked as the cover
|
||||
@ -354,12 +472,15 @@ class GenericMetadata:
|
||||
return coverlist
|
||||
|
||||
def add_credit(self, person: str, role: str, primary: bool = False) -> None:
|
||||
if person == "":
|
||||
return
|
||||
|
||||
credit = Credit(person=person, role=role, primary=primary)
|
||||
|
||||
# look to see if it's not already there...
|
||||
found = False
|
||||
for c in self.credits:
|
||||
if c["person"].casefold() == person.casefold() and c["role"].casefold() == role.casefold():
|
||||
if norm_fold(c["person"]) == norm_fold(person) and norm_fold(c["role"]) == norm_fold(role):
|
||||
# no need to add it. just adjust the "primary" flag as needed
|
||||
c["primary"] = primary
|
||||
found = True
|
||||
|
@ -223,6 +223,11 @@ def parse_filename(
|
||||
return fni
|
||||
|
||||
|
||||
def norm_fold(string: str) -> str:
|
||||
"""Normalise and casefold string"""
|
||||
return unicodedata.normalize("NFKD", string).casefold()
|
||||
|
||||
|
||||
def combine_notes(existing_notes: str | None, new_notes: str | None, split: str) -> str:
|
||||
split_notes, split_str, untouched_notes = (existing_notes or "").rpartition(split)
|
||||
if split_notes or split_str:
|
||||
|
@ -81,7 +81,7 @@ class AutoTagMatchWindow(QtWidgets.QDialog):
|
||||
self.buttonBox.button(QtWidgets.QDialogButtonBox.StandardButton.Ok).setText("Accept and Write Tags")
|
||||
|
||||
self.match_set_list = match_set_list
|
||||
self.load_data_styles = load_styles
|
||||
self._styles = styles
|
||||
self.fetch_func = fetch_func
|
||||
|
||||
self.current_match_set_idx = 0
|
||||
@ -262,8 +262,8 @@ class AutoTagMatchWindow(QtWidgets.QDialog):
|
||||
return
|
||||
|
||||
QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.CursorShape.WaitCursor))
|
||||
md.overlay(ct_md)
|
||||
for style in self.load_data_styles:
|
||||
md.overlay(ct_md, self.config.Metadata_Options__source_overlay)
|
||||
for style in self._styles:
|
||||
success = ca.write_metadata(md, style)
|
||||
QtWidgets.QApplication.restoreOverrideCursor()
|
||||
if not success:
|
||||
|
@ -30,7 +30,7 @@ class CBLTransformer:
|
||||
self.config = config
|
||||
|
||||
def apply(self) -> GenericMetadata:
|
||||
if self.config.Comic_Book_Lover__assume_lone_credit_is_primary:
|
||||
if self.config.Metadata_Options__cbl_assume_lone_credit_is_primary:
|
||||
# helper
|
||||
def set_lone_primary(role_list: list[str]) -> tuple[Credit | None, int]:
|
||||
lone_credit: Credit | None = None
|
||||
@ -56,19 +56,19 @@ class CBLTransformer:
|
||||
c["primary"] = False
|
||||
self.metadata.add_credit(c["person"], "Artist", True)
|
||||
|
||||
if self.config.Comic_Book_Lover__copy_characters_to_tags:
|
||||
if self.config.Metadata_Options__cbl_copy_characters_to_tags:
|
||||
self.metadata.tags.update(x for x in self.metadata.characters)
|
||||
|
||||
if self.config.Comic_Book_Lover__copy_teams_to_tags:
|
||||
if self.config.Metadata_Options__cbl_copy_teams_to_tags:
|
||||
self.metadata.tags.update(x for x in self.metadata.teams)
|
||||
|
||||
if self.config.Comic_Book_Lover__copy_locations_to_tags:
|
||||
if self.config.Metadata_Options__cbl_copy_locations_to_tags:
|
||||
self.metadata.tags.update(x for x in self.metadata.locations)
|
||||
|
||||
if self.config.Comic_Book_Lover__copy_storyarcs_to_tags:
|
||||
if self.config.Metadata_Options__cbl_copy_storyarcs_to_tags:
|
||||
self.metadata.tags.update(x for x in self.metadata.story_arcs)
|
||||
|
||||
if self.config.Comic_Book_Lover__copy_notes_to_comments:
|
||||
if self.config.Metadata_Options__cbl_copy_notes_to_comments:
|
||||
if self.metadata.notes is not None:
|
||||
if self.metadata.description is None:
|
||||
self.metadata.description = ""
|
||||
@ -77,7 +77,7 @@ class CBLTransformer:
|
||||
if self.metadata.notes not in self.metadata.description:
|
||||
self.metadata.description += self.metadata.notes
|
||||
|
||||
if self.config.Comic_Book_Lover__copy_weblink_to_comments:
|
||||
if self.config.Metadata_Options__cbl_copy_weblink_to_comments:
|
||||
for web_link in self.metadata.web_links:
|
||||
temp_desc = self.metadata.description
|
||||
if temp_desc is None:
|
||||
|
@ -127,7 +127,7 @@ class CLI:
|
||||
logger.exception(f"Error retrieving issue details. Save aborted.\n{e}")
|
||||
return GenericMetadata()
|
||||
|
||||
if self.config.Comic_Book_Lover__apply_transform_on_import:
|
||||
if self.config.Metadata_Options__cbl_apply_transform_on_import:
|
||||
ct_md = CBLTransformer(ct_md, self.config).apply()
|
||||
|
||||
return ct_md
|
||||
@ -253,11 +253,12 @@ class CLI:
|
||||
if ca.has_metadata(style):
|
||||
try:
|
||||
t_md = ca.read_metadata(style)
|
||||
md.overlay(t_md)
|
||||
md.overlay(t_md, self.config.Metadata_Options__read_style_overlay)
|
||||
break
|
||||
except Exception as e:
|
||||
logger.error("Failed to load metadata for %s: %s", ca.path, e)
|
||||
|
||||
# finally, use explicit stuff
|
||||
# finally, use explicit stuff (always 'overlay' mode)
|
||||
md.overlay(self.config.Runtime_Options__metadata)
|
||||
|
||||
return md
|
||||
@ -340,7 +341,7 @@ class CLI:
|
||||
|
||||
src_style_name = md_styles[self.config.Commands__copy].name()
|
||||
if not self.config.Runtime_Options__dryrun:
|
||||
if self.config.Comic_Book_Lover__apply_transform_on_bulk_operation == "cbi":
|
||||
if self.config.Metadata_Options__cbl_apply_transform_on_bulk_operation == "cbi":
|
||||
md = CBLTransformer(md, self.config).apply()
|
||||
|
||||
if ca.write_metadata(md, style):
|
||||
|
@ -3,6 +3,7 @@ from __future__ import annotations
|
||||
import json
|
||||
import logging
|
||||
import pathlib
|
||||
from enum import Enum
|
||||
from typing import Any
|
||||
|
||||
import settngs
|
||||
@ -55,7 +56,11 @@ def validate_types(config: settngs.Config[settngs.Values]) -> settngs.Config[set
|
||||
if setting.type is not None:
|
||||
# If it is not the default and the type attribute is not None
|
||||
# use it to convert the loaded string into the expected value
|
||||
if isinstance(value, str):
|
||||
if (
|
||||
isinstance(value, str)
|
||||
or isinstance(default, Enum)
|
||||
or (isinstance(setting.type, type) and issubclass(setting.type, Enum))
|
||||
):
|
||||
config.values[setting.group][setting.dest] = setting.type(value)
|
||||
return config
|
||||
|
||||
|
@ -6,6 +6,7 @@ import uuid
|
||||
import settngs
|
||||
|
||||
from comicapi import utils
|
||||
from comicapi.genericmetadata import OverlayMode
|
||||
from comictaggerlib.ctsettings.settngs_namespace import SettngsNS as ct_ns
|
||||
from comictaggerlib.defaults import DEFAULT_REPLACEMENTS, Replacement, Replacements
|
||||
|
||||
@ -13,13 +14,6 @@ from comictaggerlib.defaults import DEFAULT_REPLACEMENTS, Replacement, Replaceme
|
||||
def general(parser: settngs.Manager) -> None:
|
||||
# General Settings
|
||||
parser.add_setting("check_for_new_version", default=False, cmdline=False)
|
||||
parser.add_setting(
|
||||
"--disable-cr",
|
||||
default=False,
|
||||
action=argparse.BooleanOptionalAction,
|
||||
help="Disable the ComicRack metadata type",
|
||||
)
|
||||
parser.add_setting("use_short_metadata_names", default=False, action=argparse.BooleanOptionalAction, cmdline=False)
|
||||
parser.add_setting(
|
||||
"--prompt-on-save",
|
||||
default=True,
|
||||
@ -164,17 +158,38 @@ def talker(parser: settngs.Manager) -> None:
|
||||
)
|
||||
|
||||
|
||||
def cbl(parser: settngs.Manager) -> None:
|
||||
def md_options(parser: settngs.Manager) -> None:
|
||||
# CBL Transform settings
|
||||
parser.add_setting("--assume-lone-credit-is-primary", default=False, action=argparse.BooleanOptionalAction)
|
||||
parser.add_setting("--copy-characters-to-tags", default=False, action=argparse.BooleanOptionalAction)
|
||||
parser.add_setting("--copy-teams-to-tags", default=False, action=argparse.BooleanOptionalAction)
|
||||
parser.add_setting("--copy-locations-to-tags", default=False, action=argparse.BooleanOptionalAction)
|
||||
parser.add_setting("--copy-storyarcs-to-tags", default=False, action=argparse.BooleanOptionalAction)
|
||||
parser.add_setting("--copy-notes-to-comments", default=False, action=argparse.BooleanOptionalAction)
|
||||
parser.add_setting("--copy-weblink-to-comments", default=False, action=argparse.BooleanOptionalAction)
|
||||
parser.add_setting("--apply-transform-on-import", default=False, action=argparse.BooleanOptionalAction)
|
||||
parser.add_setting("--apply-transform-on-bulk-operation", default=False, action=argparse.BooleanOptionalAction)
|
||||
parser.add_setting("--cbl-assume-lone-credit-is-primary", default=False, action=argparse.BooleanOptionalAction)
|
||||
parser.add_setting("--cbl-copy-characters-to-tags", default=False, action=argparse.BooleanOptionalAction)
|
||||
parser.add_setting("--cbl-copy-teams-to-tags", default=False, action=argparse.BooleanOptionalAction)
|
||||
parser.add_setting("--cbl-copy-locations-to-tags", default=False, action=argparse.BooleanOptionalAction)
|
||||
parser.add_setting("--cbl-copy-storyarcs-to-tags", default=False, action=argparse.BooleanOptionalAction)
|
||||
parser.add_setting("--cbl-copy-notes-to-comments", default=False, action=argparse.BooleanOptionalAction)
|
||||
parser.add_setting("--cbl-copy-weblink-to-comments", default=False, action=argparse.BooleanOptionalAction)
|
||||
parser.add_setting("--cbl-apply-transform-on-import", default=False, action=argparse.BooleanOptionalAction)
|
||||
parser.add_setting("--cbl-apply-transform-on-bulk-operation", default=False, action=argparse.BooleanOptionalAction)
|
||||
|
||||
parser.add_setting(
|
||||
"--read-style-overlay",
|
||||
default=OverlayMode.overlay,
|
||||
type=OverlayMode,
|
||||
help="How to overlay new metadata on the current for enabled read styles (CR, CBL, etc.)",
|
||||
)
|
||||
parser.add_setting(
|
||||
"--source-overlay",
|
||||
default=OverlayMode.overlay,
|
||||
type=OverlayMode,
|
||||
help="How to overlay the new metadata from a source (CV, Metron, GCD, etc.) on to the current",
|
||||
)
|
||||
|
||||
parser.add_setting("use_short_metadata_names", default=False, action=argparse.BooleanOptionalAction, cmdline=False)
|
||||
parser.add_setting(
|
||||
"--disable-cr",
|
||||
default=False,
|
||||
action=argparse.BooleanOptionalAction,
|
||||
help="Disable the ComicRack metadata type",
|
||||
)
|
||||
|
||||
|
||||
def rename(parser: settngs.Manager) -> None:
|
||||
@ -311,7 +326,7 @@ def register_file_settings(parser: settngs.Manager) -> None:
|
||||
parser.add_group("Issue Identifier", identifier, False)
|
||||
parser.add_group("Filename Parsing", filename, False)
|
||||
parser.add_group("Sources", talker, False)
|
||||
parser.add_group("Comic Book Lover", cbl, False)
|
||||
parser.add_group("Metadata Options", md_options, False)
|
||||
parser.add_group("File Rename", rename, False)
|
||||
parser.add_group("Auto-Tag", autotag, False)
|
||||
parser.add_group("General", general, False)
|
||||
|
@ -9,6 +9,7 @@ import comicapi.utils
|
||||
import comictaggerlib.ctsettings.types
|
||||
import comictaggerlib.defaults
|
||||
import comictaggerlib.resulttypes
|
||||
from comicapi.genericmetadata import OverlayMode
|
||||
|
||||
|
||||
class SettngsNS(settngs.TypedNS):
|
||||
@ -74,15 +75,19 @@ class SettngsNS(settngs.TypedNS):
|
||||
Sources__source: str
|
||||
Sources__remove_html_tables: bool
|
||||
|
||||
Comic_Book_Lover__assume_lone_credit_is_primary: bool
|
||||
Comic_Book_Lover__copy_characters_to_tags: bool
|
||||
Comic_Book_Lover__copy_teams_to_tags: bool
|
||||
Comic_Book_Lover__copy_locations_to_tags: bool
|
||||
Comic_Book_Lover__copy_storyarcs_to_tags: bool
|
||||
Comic_Book_Lover__copy_notes_to_comments: bool
|
||||
Comic_Book_Lover__copy_weblink_to_comments: bool
|
||||
Comic_Book_Lover__apply_transform_on_import: bool
|
||||
Comic_Book_Lover__apply_transform_on_bulk_operation: bool
|
||||
Metadata_Options__cbl_assume_lone_credit_is_primary: bool
|
||||
Metadata_Options__cbl_copy_characters_to_tags: bool
|
||||
Metadata_Options__cbl_copy_teams_to_tags: bool
|
||||
Metadata_Options__cbl_copy_locations_to_tags: bool
|
||||
Metadata_Options__cbl_copy_storyarcs_to_tags: bool
|
||||
Metadata_Options__cbl_copy_notes_to_comments: bool
|
||||
Metadata_Options__cbl_copy_weblink_to_comments: bool
|
||||
Metadata_Options__cbl_apply_transform_on_import: bool
|
||||
Metadata_Options__cbl_apply_transform_on_bulk_operation: bool
|
||||
Metadata_Options__read_style_overlay: OverlayMode
|
||||
Metadata_Options__source_overlay: OverlayMode
|
||||
Metadata_Options__use_short_metadata_names: bool
|
||||
Metadata_Options__disable_cr: bool
|
||||
|
||||
File_Rename__template: str
|
||||
File_Rename__issue_number_padding: int
|
||||
@ -101,8 +106,6 @@ class SettngsNS(settngs.TypedNS):
|
||||
Auto_Tag__remove_archive_after_successful_match: bool
|
||||
|
||||
General__check_for_new_version: bool
|
||||
General__disable_cr: bool
|
||||
General__use_short_metadata_names: bool
|
||||
General__prompt_on_save: bool
|
||||
|
||||
Dialog_Flags__show_disclaimer: bool
|
||||
@ -189,16 +192,19 @@ class Sources(typing.TypedDict):
|
||||
remove_html_tables: bool
|
||||
|
||||
|
||||
class Comic_Book_Lover(typing.TypedDict):
|
||||
assume_lone_credit_is_primary: bool
|
||||
copy_characters_to_tags: bool
|
||||
copy_teams_to_tags: bool
|
||||
copy_locations_to_tags: bool
|
||||
copy_storyarcs_to_tags: bool
|
||||
copy_notes_to_comments: bool
|
||||
copy_weblink_to_comments: bool
|
||||
apply_transform_on_import: bool
|
||||
apply_transform_on_bulk_operation: bool
|
||||
class Metadata_Options(typing.TypedDict):
|
||||
cbl_assume_lone_credit_is_primary: bool
|
||||
cbl_copy_characters_to_tags: bool
|
||||
cbl_copy_teams_to_tags: bool
|
||||
cbl_copy_locations_to_tags: bool
|
||||
cbl_copy_storyarcs_to_tags: bool
|
||||
cbl_copy_notes_to_comments: bool
|
||||
cbl_copy_weblink_to_comments: bool
|
||||
cbl_apply_transform_on_import: bool
|
||||
cbl_apply_transform_on_bulk_operation: bool
|
||||
metadata_overlay: OverlayMode
|
||||
use_short_metadata_names: bool
|
||||
disable_cr: bool
|
||||
|
||||
|
||||
class File_Rename(typing.TypedDict):
|
||||
@ -223,8 +229,6 @@ class Auto_Tag(typing.TypedDict):
|
||||
|
||||
class General(typing.TypedDict):
|
||||
check_for_new_version: bool
|
||||
disable_cr: bool
|
||||
use_short_metadata_names: bool
|
||||
prompt_on_save: bool
|
||||
|
||||
|
||||
@ -253,7 +257,7 @@ SettngsDict = typing.TypedDict(
|
||||
"Issue Identifier": Issue_Identifier,
|
||||
"Filename Parsing": Filename_Parsing,
|
||||
"Sources": Sources,
|
||||
"Comic Book Lover": Comic_Book_Lover,
|
||||
"Metadata Options": Metadata_Options,
|
||||
"File Rename": File_Rename,
|
||||
"Auto-Tag": Auto_Tag,
|
||||
"General": General,
|
||||
|
@ -252,7 +252,7 @@ class App:
|
||||
# config already loaded
|
||||
error = None
|
||||
|
||||
if self.config[0].General__disable_cr:
|
||||
if self.config[0].Metadata_Options__disable_cr:
|
||||
if "cr" in comicapi.comicarchive.metadata_styles:
|
||||
del comicapi.comicarchive.metadata_styles["cr"]
|
||||
|
||||
|
@ -30,7 +30,8 @@ from PyQt5 import QtCore, QtGui, QtWidgets, uic
|
||||
import comictaggerlib.ui.talkeruigenerator
|
||||
from comicapi import utils
|
||||
from comicapi.archivers.archiver import Archiver
|
||||
from comicapi.genericmetadata import md_test
|
||||
# TODO OverlayMode changed to merge
|
||||
from comicapi.genericmetadata import OverlayMode, md_test
|
||||
from comictaggerlib import ctsettings
|
||||
from comictaggerlib.ctsettings import ct_ns
|
||||
from comictaggerlib.ctsettings.plugin import group_for_plugin
|
||||
@ -194,6 +195,10 @@ class SettingsWindow(QtWidgets.QDialog):
|
||||
)
|
||||
self.cbFilenameParser.clear()
|
||||
self.cbFilenameParser.addItems(utils.Parser)
|
||||
# TODO check
|
||||
for mode in OverlayMode:
|
||||
self.cbxOverlayReadStyle.addItem(mode.name.capitalize().replace("_", " "), mode.value)
|
||||
self.cbxOverlaySource.addItem(mode.name.capitalize().replace("_", " "), mode.value)
|
||||
self.connect_signals()
|
||||
self.settings_to_form()
|
||||
self.rename_test()
|
||||
@ -399,7 +404,6 @@ class SettingsWindow(QtWidgets.QDialog):
|
||||
self.tePublisherFilter.setPlainText("\n".join(self.config[0].Issue_Identifier__publisher_filter))
|
||||
|
||||
self.cbxCheckForNewVersion.setChecked(self.config[0].General__check_for_new_version)
|
||||
self.cbxShortMetadataNames.setChecked(self.config[0].General__use_short_metadata_names)
|
||||
|
||||
self.cbFilenameParser.setCurrentText(self.config[0].Filename_Parsing__filename_parser)
|
||||
self.cbxRemoveC2C.setChecked(self.config[0].Filename_Parsing__remove_c2c)
|
||||
@ -417,17 +421,25 @@ class SettingsWindow(QtWidgets.QDialog):
|
||||
self.cbxExactMatches.setChecked(self.config[0].Issue_Identifier__exact_series_matches_first)
|
||||
self.cbxClearFormBeforePopulating.setChecked(self.config[0].Issue_Identifier__clear_metadata)
|
||||
|
||||
self.cbxAssumeLoneCreditIsPrimary.setChecked(self.config[0].Comic_Book_Lover__assume_lone_credit_is_primary)
|
||||
self.cbxCopyCharactersToTags.setChecked(self.config[0].Comic_Book_Lover__copy_characters_to_tags)
|
||||
self.cbxCopyTeamsToTags.setChecked(self.config[0].Comic_Book_Lover__copy_teams_to_tags)
|
||||
self.cbxCopyLocationsToTags.setChecked(self.config[0].Comic_Book_Lover__copy_locations_to_tags)
|
||||
self.cbxCopyStoryArcsToTags.setChecked(self.config[0].Comic_Book_Lover__copy_storyarcs_to_tags)
|
||||
self.cbxCopyNotesToComments.setChecked(self.config[0].Comic_Book_Lover__copy_notes_to_comments)
|
||||
self.cbxCopyWebLinkToComments.setChecked(self.config[0].Comic_Book_Lover__copy_weblink_to_comments)
|
||||
self.cbxApplyCBLTransformOnCVIMport.setChecked(self.config[0].Comic_Book_Lover__apply_transform_on_import)
|
||||
self.cbxAssumeLoneCreditIsPrimary.setChecked(self.config[0].Metadata_Options__cbl_assume_lone_credit_is_primary)
|
||||
self.cbxCopyCharactersToTags.setChecked(self.config[0].Metadata_Options__cbl_copy_characters_to_tags)
|
||||
self.cbxCopyTeamsToTags.setChecked(self.config[0].Metadata_Options__cbl_copy_teams_to_tags)
|
||||
self.cbxCopyLocationsToTags.setChecked(self.config[0].Metadata_Options__cbl_copy_locations_to_tags)
|
||||
self.cbxCopyStoryArcsToTags.setChecked(self.config[0].Metadata_Options__cbl_copy_storyarcs_to_tags)
|
||||
self.cbxCopyNotesToComments.setChecked(self.config[0].Metadata_Options__cbl_copy_notes_to_comments)
|
||||
self.cbxCopyWebLinkToComments.setChecked(self.config[0].Metadata_Options__cbl_copy_weblink_to_comments)
|
||||
self.cbxApplyCBLTransformOnCVIMport.setChecked(self.config[0].Metadata_Options__cbl_apply_transform_on_import)
|
||||
self.cbxApplyCBLTransformOnBatchOperation.setChecked(
|
||||
self.config[0].Comic_Book_Lover__apply_transform_on_bulk_operation
|
||||
self.config[0].Metadata_Options__cbl_apply_transform_on_bulk_operation
|
||||
)
|
||||
self.cbxOverlayReadStyle.setCurrentIndex(
|
||||
self.cbxOverlayReadStyle.findData(self.config[0].Metadata_Options__read_style_overlay.value)
|
||||
)
|
||||
self.cbxOverlaySource.setCurrentIndex(
|
||||
self.cbxOverlaySource.findData(self.config[0].Metadata_Options__source_overlay.value)
|
||||
)
|
||||
self.cbxShortMetadataNames.setChecked(self.config[0].Metadata_Options__use_short_metadata_names)
|
||||
self.cbxDisableCR.setChecked(self.config[0].Metadata_Options__disable_cr)
|
||||
|
||||
self.leRenameTemplate.setText(self.config[0].File_Rename__template)
|
||||
self.leIssueNumPadding.setText(str(self.config[0].File_Rename__issue_number_padding))
|
||||
@ -544,18 +556,29 @@ class SettingsWindow(QtWidgets.QDialog):
|
||||
self.config[0].Issue_Identifier__exact_series_matches_first = self.cbxExactMatches.isChecked()
|
||||
self.config[0].Issue_Identifier__clear_metadata = self.cbxClearFormBeforePopulating.isChecked()
|
||||
|
||||
self.config[0].Comic_Book_Lover__assume_lone_credit_is_primary = self.cbxAssumeLoneCreditIsPrimary.isChecked()
|
||||
self.config[0].Comic_Book_Lover__copy_characters_to_tags = self.cbxCopyCharactersToTags.isChecked()
|
||||
self.config[0].Comic_Book_Lover__copy_teams_to_tags = self.cbxCopyTeamsToTags.isChecked()
|
||||
self.config[0].Comic_Book_Lover__copy_locations_to_tags = self.cbxCopyLocationsToTags.isChecked()
|
||||
self.config[0].Comic_Book_Lover__copy_storyarcs_to_tags = self.cbxCopyStoryArcsToTags.isChecked()
|
||||
self.config[0].Comic_Book_Lover__copy_notes_to_comments = self.cbxCopyNotesToComments.isChecked()
|
||||
self.config[0].Comic_Book_Lover__copy_weblink_to_comments = self.cbxCopyWebLinkToComments.isChecked()
|
||||
self.config[0].Comic_Book_Lover__apply_transform_on_import = self.cbxApplyCBLTransformOnCVIMport.isChecked()
|
||||
self.config.values.Comic_Book_Lover__apply_transform_on_bulk_operation = (
|
||||
self.config[0].Metadata_Options__cbl_assume_lone_credit_is_primary = (
|
||||
self.cbxAssumeLoneCreditIsPrimary.isChecked()
|
||||
)
|
||||
self.config[0].Metadata_Options__cbl_copy_characters_to_tags = self.cbxCopyCharactersToTags.isChecked()
|
||||
self.config[0].Metadata_Options__cbl_copy_teams_to_tags = self.cbxCopyTeamsToTags.isChecked()
|
||||
self.config[0].Metadata_Options__cbl_copy_locations_to_tags = self.cbxCopyLocationsToTags.isChecked()
|
||||
self.config[0].Metadata_Options__cbl_copy_storyarcs_to_tags = self.cbxCopyStoryArcsToTags.isChecked()
|
||||
self.config[0].Metadata_Options__cbl_copy_notes_to_comments = self.cbxCopyNotesToComments.isChecked()
|
||||
self.config[0].Metadata_Options__cbl_copy_weblink_to_comments = self.cbxCopyWebLinkToComments.isChecked()
|
||||
self.config[0].Metadata_Options__cbl_apply_transform_on_import = self.cbxApplyCBLTransformOnCVIMport.isChecked()
|
||||
self.config.values.Metadata_Options__cbl_apply_transform_on_bulk_operation = (
|
||||
self.cbxApplyCBLTransformOnBatchOperation.isChecked()
|
||||
)
|
||||
|
||||
self.config[0].Metadata_Options__read_style_overlay = OverlayMode[self.cbxOverlayReadStyle.currentData()]
|
||||
self.config[0].Metadata_Options__source_overlay = OverlayMode[self.cbxOverlaySource.currentData()]
|
||||
self.config[0].Metadata_Options__disable_cr = self.cbxDisableCR.isChecked()
|
||||
# Update metadata style names if required
|
||||
if self.config[0].Metadata_Options__use_short_metadata_names != self.cbxShortMetadataNames.isChecked():
|
||||
self.config[0].Metadata_Options__use_short_metadata_names = self.cbxShortMetadataNames.isChecked()
|
||||
self.parent().populate_style_names()
|
||||
self.parent().adjust_save_style_combo()
|
||||
|
||||
self.config[0].File_Rename__template = str(self.leRenameTemplate.text())
|
||||
self.config[0].File_Rename__issue_number_padding = int(self.leIssueNumPadding.text())
|
||||
self.config[0].File_Rename__use_smart_string_cleanup = self.cbxSmartCleanup.isChecked()
|
||||
|
@ -1431,7 +1431,7 @@ class TaggerWindow(QtWidgets.QMainWindow):
|
||||
self.cbLoadDataStyle.clear()
|
||||
# Add the entries to the tag style combobox
|
||||
for style in metadata_styles.values():
|
||||
if self.config[0].General__use_short_metadata_names:
|
||||
if self.config[0].Metadata_Options__use_short_metadata_names:
|
||||
self.cbSaveDataStyle.addItem(style.short_name.upper(), style.short_name)
|
||||
self.cbLoadDataStyle.addItem(style.short_name.upper(), style.short_name)
|
||||
else:
|
||||
@ -1701,7 +1701,7 @@ class TaggerWindow(QtWidgets.QMainWindow):
|
||||
center_window_on_parent(prog_dialog)
|
||||
QtCore.QCoreApplication.processEvents()
|
||||
|
||||
if style == "cbi" and self.config[0].Comic_Book_Lover__apply_transform_on_bulk_operation:
|
||||
if style == "cbi" and self.config[0].Metadata_Options__cbl_apply_transform_on_bulk_operation:
|
||||
md = CBLTransformer(md, self.config[0]).apply()
|
||||
|
||||
if ca.write_metadata(md, style):
|
||||
|
@ -7,7 +7,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>703</width>
|
||||
<height>574</height>
|
||||
<height>597</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@ -28,7 +28,7 @@
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
<number>4</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="tGeneral">
|
||||
<attribute name="title">
|
||||
@ -48,43 +48,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="cbxShortMetadataNames">
|
||||
<property name="toolTip">
|
||||
<string>Use the short name for the metadata styles (CBI, CR, etc.)</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Use "short" names for metadata styles</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QPushButton" name="btnResetSettings">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Default Settings</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QPushButton" name="btnClearCache">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Clear Cache</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<item row="2" column="1">
|
||||
<widget class="QLabel" name="lblDefaultSettings">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
@ -103,7 +67,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<item row="3" column="1">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
@ -122,13 +86,39 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="cbxPromptOnSave">
|
||||
<property name="text">
|
||||
<string>Prompts the user to confirm saving tags</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QPushButton" name="btnResetSettings">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Default Settings</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QPushButton" name="btnClearCache">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Clear Cache</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
@ -427,19 +417,124 @@
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4"/>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tMDType">
|
||||
<widget class="QWidget" name="tMDOptions">
|
||||
<attribute name="title">
|
||||
<string>Metadata Types</string>
|
||||
<string>Metadata Options</string>
|
||||
</attribute>
|
||||
<layout class="QGridLayout" name="gridLayout_6">
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="cbxApplyCBLTransformOnBatchOperation">
|
||||
<property name="text">
|
||||
<string>Apply CBL Transforms on Batch Copy Operations to CBL Tags</string>
|
||||
<item row="0" column="0" rowspan="4">
|
||||
<widget class="QGroupBox" name="groupBox_5">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>General</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_7">
|
||||
<property name="leftMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="cbxShortMetadataNames">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Use the short name for the metadata styles (CBI, CR, etc.)</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Use "short" names for metadata styles</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QCheckBox" name="cbxDisableCR">
|
||||
<property name="toolTip">
|
||||
<string>Useful if you use the CIX metadata type</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Disable ComicRack Metadata Type</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<item row="5" column="0" rowspan="2">
|
||||
<widget class="QGroupBox" name="groupBox_4">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>80</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>CBL Options</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_11">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="cbxApplyCBLTransformOnCVIMport">
|
||||
<property name="text">
|
||||
<string>Apply CBL Transforms on ComicVine Import</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="cbxApplyCBLTransformOnBatchOperation">
|
||||
<property name="text">
|
||||
<string>Apply CBL Transforms on Batch Copy Operations to CBL Tags</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
|
||||
@ -450,99 +545,347 @@
|
||||
<property name="title">
|
||||
<string>CBL Transforms</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="layoutWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>11</x>
|
||||
<y>21</y>
|
||||
<width>251</width>
|
||||
<height>206</height>
|
||||
</rect>
|
||||
<layout class="QGridLayout" name="gridLayout_9">
|
||||
<property name="leftMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_7">
|
||||
<item row="3" column="0">
|
||||
<widget class="QCheckBox" name="cbxCopyLocationsToTags">
|
||||
<property name="text">
|
||||
<string>Copy Locations to Generic Tags</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="cbxAssumeLoneCreditIsPrimary">
|
||||
<property name="text">
|
||||
<string>Assume Lone Credit Is Primary</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="cbxCopyCharactersToTags">
|
||||
<property name="text">
|
||||
<string>Copy Characters to Generic Tags</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QCheckBox" name="cbxCopyTeamsToTags">
|
||||
<property name="text">
|
||||
<string>Copy Teams to Generic Tags</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QCheckBox" name="cbxCopyNotesToComments">
|
||||
<property name="text">
|
||||
<string>Copy Notes to Comments</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QCheckBox" name="cbxCopyWebLinkToComments">
|
||||
<property name="text">
|
||||
<string>Copy Web Link to Comments</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QCheckBox" name="cbxCopyStoryArcsToTags">
|
||||
<property name="text">
|
||||
<string>Copy Story Arcs to Generic Tags</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<property name="topMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="1" column="1">
|
||||
<widget class="QCheckBox" name="cbxCopyNotesToComments">
|
||||
<property name="text">
|
||||
<string>Copy Notes to Comments</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QCheckBox" name="cbxCopyWebLinkToComments">
|
||||
<property name="text">
|
||||
<string>Copy Web Link to Comments</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QCheckBox" name="cbxCopyLocationsToTags">
|
||||
<property name="text">
|
||||
<string>Copy Locations to Generic Tags</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="cbxAssumeLoneCreditIsPrimary">
|
||||
<property name="text">
|
||||
<string>Assume Lone Credit Is Primary</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QCheckBox" name="cbxCopyStoryArcsToTags">
|
||||
<property name="text">
|
||||
<string>Copy Story Arcs to Generic Tags</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="cbxCopyCharactersToTags">
|
||||
<property name="text">
|
||||
<string>Copy Characters to Generic Tags</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QCheckBox" name="cbxCopyTeamsToTags">
|
||||
<property name="text">
|
||||
<string>Copy Teams to Generic Tags</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<item row="4" column="0">
|
||||
<widget class="QGroupBox" name="groupBox_6">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>165</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Overlay</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_10">
|
||||
<property name="leftMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="lblOverlaySource">
|
||||
<property name="toolTip">
|
||||
<string>The operation to perform when overlaying source data (Comic Vine, Metron, GCD, etc.)</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Data Source</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="lblOverlayReadStyle">
|
||||
<property name="toolTip">
|
||||
<string>The operation to perform when overlaying read styles (ComicRack, ComicBookInfo, etc.)</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Read Style</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="cbxOverlaySource">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>The operation to perform when overlaying source data (Comic Vine, Metron, GCD, etc.)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2" rowspan="3">
|
||||
<widget class="QTabWidget" name="tabWidgetOverlay">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>200</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="tabPosition">
|
||||
<enum>QTabWidget::North</enum>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="documentMode">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="tabBarAutoHide">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<widget class="QWidget" name="tOverlay">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<attribute name="title">
|
||||
<string>Overlay</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QPlainTextEdit" name="overlayTextEdit">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>1</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="undoRedoEnabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="plainText">
|
||||
<string>Read Style: Overlays all the none empty values of the read style metadata on top of the current metadata (i.e. file name parsing, other read style(s)).
|
||||
Data Source: Overlays all the none empty values from the data source (e.g. Comic Vine) on top of the current metadata (i.e. file name parsing, read style(s)).
|
||||
|
||||
Example:
|
||||
(Series=batman, Issue=1, Tags=[batman,joker,robin])
|
||||
+ (Series=Batman, Publisher=DC Comics, Tags=[mystery,action])
|
||||
= (Series=Batman, Issue=1, Publisher=DC Comics, Tags=[mystery,action])</string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tAdd">
|
||||
<attribute name="title">
|
||||
<string>Add Missing</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_9">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QPlainTextEdit" name="addTextEdit">
|
||||
<property name="plainText">
|
||||
<string>Read Style: Adds any metadata that is present in the read style but is missing in the current metadata (i.e. file name parsing, other read style(s)).
|
||||
Data Source: Add any metadata that is present in the data source (e.g. Comic Vine) but is missing in the current metadata (i.e. file name parsing, read style(s)).
|
||||
|
||||
Example:
|
||||
(Series=batman, Issue=1, Tags=[batman,joker,robin])
|
||||
+ (Series=Superman, Issue=10, Publisher=DC Comics, Tags=[superman,lois lane,lex luthor])
|
||||
= (Series=batman, Issue=1, Publisher=DC Comics, Tags=[batman,joker,robin])</string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tCombine">
|
||||
<attribute name="title">
|
||||
<string>Combine</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_10">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QPlainTextEdit" name="combineTextEdit">
|
||||
<property name="plainText">
|
||||
<string>Read Style: Same as Overlay except lists (tags, characters, genres, credits, etc.) are combined with the current metadata (i.e. file name parsing, other read style(s)).
|
||||
Data Source: Same as Overlay except lists (tags, characters, genres, credits, etc.) are combined with the current metadata (i.e. file name parsing, read style(s)).
|
||||
|
||||
Example:
|
||||
(Series=batman, Issue=1, Tags=[batman,joker,robin])
|
||||
+ (Series=Batman, Publisher=DC Comics, Tags=[mystery,action])
|
||||
= (Series=Batman, Issue=1, Publisher=DC Comics, Tags=[batman,joker,robin,mystery,action])</string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="cbxOverlayReadStyle">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>The operation to perform when overlaying read styles (ComicRack, ComicBookInfo, etc.)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="0">
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>10</height>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="cbxApplyCBLTransformOnCVIMport">
|
||||
<property name="text">
|
||||
<string>Apply CBL Transforms on ComicVine Import</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QCheckBox" name="cbxDisableCR">
|
||||
<property name="text">
|
||||
<string>Disable ComicRack Metadata Type (useful if you use the CIX metadata type)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tRename">
|
||||
|
@ -5,6 +5,7 @@ import textwrap
|
||||
import pytest
|
||||
|
||||
import comicapi.genericmetadata
|
||||
from comicapi.genericmetadata import OverlayMode, parse_url
|
||||
from testing.comicdata import credits, metadata
|
||||
|
||||
|
||||
@ -24,6 +25,107 @@ def test_metadata_overlay(md: comicapi.genericmetadata.GenericMetadata, replaced
|
||||
assert md == expected
|
||||
|
||||
|
||||
def test_metadata_overlay_add_missing():
|
||||
md = comicapi.genericmetadata.GenericMetadata(series="test", issue="1", title="test", genres={"test", "test2"})
|
||||
add = comicapi.genericmetadata.GenericMetadata(
|
||||
series="test2", issue="2", title="test2", genres={"test3", "test4"}, issue_count=5
|
||||
)
|
||||
expected = comicapi.genericmetadata.GenericMetadata(
|
||||
series="test", issue="1", title="test", genres={"test", "test2"}, issue_count=5
|
||||
)
|
||||
md.overlay(add, OverlayMode.add_missing)
|
||||
|
||||
assert md == expected
|
||||
|
||||
|
||||
def test_metadata_overlay_combine():
|
||||
md = comicapi.genericmetadata.GenericMetadata(
|
||||
series="test",
|
||||
issue="1",
|
||||
title="test",
|
||||
genres={"test", "test2"},
|
||||
story_arcs=["arc1"],
|
||||
characters={"Bob", "fred"},
|
||||
web_links=[parse_url("https://my.comics.here.com")],
|
||||
)
|
||||
combine_new = comicapi.genericmetadata.GenericMetadata(
|
||||
series="test2",
|
||||
title="test2",
|
||||
genres={"test2", "test3", "test4"},
|
||||
story_arcs=["arc1", "arc2"],
|
||||
characters={"bob", "fred"},
|
||||
)
|
||||
expected = comicapi.genericmetadata.GenericMetadata(
|
||||
series="test2",
|
||||
issue="1",
|
||||
title="test2",
|
||||
genres={"test", "test2", "test3", "test4"},
|
||||
story_arcs=["arc1", "arc2"],
|
||||
characters={"bob", "fred"},
|
||||
web_links=[parse_url("https://my.comics.here.com")],
|
||||
)
|
||||
md.overlay(combine_new, OverlayMode.combine)
|
||||
|
||||
assert md == expected
|
||||
|
||||
|
||||
def test_assign_dedupe_set():
|
||||
md_cur = comicapi.genericmetadata.GenericMetadata(characters={"Macintosh", "Søren Kierkegaard", "Barry"})
|
||||
md_new = comicapi.genericmetadata.GenericMetadata(characters={"MacIntosh", "Soren Kierkegaard"})
|
||||
# Expect a failure to normalise with NFKD and 'ø'
|
||||
expected = comicapi.genericmetadata.GenericMetadata(
|
||||
characters={"MacIntosh", "Soren Kierkegaard", "Søren Kierkegaard", "Barry"}
|
||||
)
|
||||
|
||||
md_cur.overlay(md_new, OverlayMode.combine)
|
||||
|
||||
assert md_cur == expected
|
||||
|
||||
|
||||
def test_assign_dedupe_list():
|
||||
md_cur = comicapi.genericmetadata.GenericMetadata(story_arcs=["arc 1", "arc2", "arc 3"])
|
||||
md_new = comicapi.genericmetadata.GenericMetadata(story_arcs=["Arc 1", "Arc2"])
|
||||
expected = comicapi.genericmetadata.GenericMetadata(story_arcs=["Arc 1", "Arc2", "arc 3"])
|
||||
|
||||
md_cur.overlay(md_new, OverlayMode.combine)
|
||||
|
||||
assert md_cur == expected
|
||||
|
||||
|
||||
def test_assign_credits_overlay():
|
||||
md = comicapi.genericmetadata.GenericMetadata()
|
||||
md.add_credit(person="test", role="writer", primary=False)
|
||||
md.add_credit(person="test", role="artist", primary=True)
|
||||
|
||||
md_new = comicapi.genericmetadata.GenericMetadata()
|
||||
md_new.add_credit(person="", role="writer")
|
||||
md_new.add_credit(person="test2", role="inker")
|
||||
|
||||
expected = comicapi.genericmetadata.GenericMetadata()
|
||||
expected.add_credit(person="test", role="writer", primary=False)
|
||||
expected.add_credit(person="test", role="artist", primary=True)
|
||||
expected.add_credit(person="test2", role="inker")
|
||||
|
||||
assert md.assign_credits_overlay(md.credits, md_new.credits) == expected.credits
|
||||
|
||||
|
||||
def test_assign_credits_add_missing():
|
||||
md = comicapi.genericmetadata.GenericMetadata()
|
||||
md.add_credit(person="test", role="writer", primary=False)
|
||||
md.add_credit(person="test", role="artist", primary=True)
|
||||
|
||||
md_new = comicapi.genericmetadata.GenericMetadata()
|
||||
md_new.add_credit(person="Bob", role="writer")
|
||||
md_new.add_credit(person="test", role="artist", primary=True)
|
||||
|
||||
expected = comicapi.genericmetadata.GenericMetadata()
|
||||
expected.add_credit(person="Bob", role="writer")
|
||||
expected.add_credit(person="test", role="artist", primary=True)
|
||||
expected.add_credit(person="test", role="writer", primary=False)
|
||||
|
||||
assert md.assign_credits_add_missing(md.credits, md_new.credits) == expected.credits
|
||||
|
||||
|
||||
def test_add_credit():
|
||||
md = comicapi.genericmetadata.GenericMetadata()
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user