comicbox.enums.maps.age_rating

[docs] module comicbox.enums.maps.age_rating

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
"""Age Rating enum maps."""

from enum import Enum
from types import MappingProxyType

from caseconverter import snakecase

from comicbox.enums.comicinfo import (
    ComicInfoAgeRatingEnum,
)
from comicbox.enums.generic.age_rating import (
    DCAgeRatingEnum,
    GenericAgeRatingEnum,
    MarvelAgeRatingEnum,
)
from comicbox.enums.metroninfo import (
    MetronAgeRatingEnum,
)

COMICINFO_AGE_RATING_MAP: MappingProxyType[Enum, Enum] = MappingProxyType(
    {
        MarvelAgeRatingEnum.ALL_AGES: ComicInfoAgeRatingEnum.EVERYONE,
        MarvelAgeRatingEnum.PG: ComicInfoAgeRatingEnum.E_10_PLUS,
        MarvelAgeRatingEnum.PG_PLUS: ComicInfoAgeRatingEnum.E_10_PLUS,
        MarvelAgeRatingEnum.PARENTAL_ADVISORY: ComicInfoAgeRatingEnum.MA_17_PLUS,
        MarvelAgeRatingEnum.PSR: ComicInfoAgeRatingEnum.MA_15_PLUS,
        MarvelAgeRatingEnum.PSR_PLUS: ComicInfoAgeRatingEnum.MA_17_PLUS,
        MarvelAgeRatingEnum.A: ComicInfoAgeRatingEnum.EVERYONE,
        MarvelAgeRatingEnum.T_PLUS: ComicInfoAgeRatingEnum.MA_17_PLUS,
        MarvelAgeRatingEnum.T: ComicInfoAgeRatingEnum.MA_15_PLUS,
        MarvelAgeRatingEnum.EXPLICIT_CONTENT: ComicInfoAgeRatingEnum.X_18_PLUS,
        DCAgeRatingEnum.E: ComicInfoAgeRatingEnum.EVERYONE,
        DCAgeRatingEnum.EVERYONE: ComicInfoAgeRatingEnum.EVERYONE,
        DCAgeRatingEnum.T: ComicInfoAgeRatingEnum.MA_15_PLUS,
        DCAgeRatingEnum.TEEN: ComicInfoAgeRatingEnum.MA_15_PLUS,
        DCAgeRatingEnum.T_PLUS: ComicInfoAgeRatingEnum.MA_17_PLUS,
        DCAgeRatingEnum.TEEN_PLUS: ComicInfoAgeRatingEnum.MA_17_PLUS,
        DCAgeRatingEnum.M: ComicInfoAgeRatingEnum.MA_17_PLUS,
        DCAgeRatingEnum.MATURE: ComicInfoAgeRatingEnum.MA_17_PLUS,
        DCAgeRatingEnum.THIRTEEN_PLUS: ComicInfoAgeRatingEnum.MA_15_PLUS,
        DCAgeRatingEnum.FIFTEEN_PLUS: ComicInfoAgeRatingEnum.MA_15_PLUS,
        DCAgeRatingEnum.SEVENTEEN_PLUS: ComicInfoAgeRatingEnum.MA_17_PLUS,
        GenericAgeRatingEnum.PG13: ComicInfoAgeRatingEnum.MA_15_PLUS,
        GenericAgeRatingEnum.R: ComicInfoAgeRatingEnum.MA_17_PLUS,
        GenericAgeRatingEnum.X: ComicInfoAgeRatingEnum.X_18_PLUS,
        GenericAgeRatingEnum.XXX: ComicInfoAgeRatingEnum.X_18_PLUS,
        GenericAgeRatingEnum.ADULT: ComicInfoAgeRatingEnum.A_18_PLUS,
        GenericAgeRatingEnum.PORN: ComicInfoAgeRatingEnum.X_18_PLUS,
        GenericAgeRatingEnum.PORNOGRAPHY: ComicInfoAgeRatingEnum.X_18_PLUS,
        GenericAgeRatingEnum.SEX: ComicInfoAgeRatingEnum.X_18_PLUS,
        GenericAgeRatingEnum.SEXUALLY_EXPLICIT: ComicInfoAgeRatingEnum.X_18_PLUS,
        GenericAgeRatingEnum.VIOLENT: ComicInfoAgeRatingEnum.A_18_PLUS,
        GenericAgeRatingEnum.VIOLENCE: ComicInfoAgeRatingEnum.A_18_PLUS,
        MetronAgeRatingEnum.EVERYONE: ComicInfoAgeRatingEnum.EVERYONE,
        MetronAgeRatingEnum.TEEN: ComicInfoAgeRatingEnum.TEEN,
        MetronAgeRatingEnum.TEEN_PLUS: ComicInfoAgeRatingEnum.MA_15_PLUS,
        MetronAgeRatingEnum.MATURE: ComicInfoAgeRatingEnum.MA_17_PLUS,
        MetronAgeRatingEnum.EXPLICIT: ComicInfoAgeRatingEnum.R_18_PLUS,
        MetronAgeRatingEnum.ADULT: ComicInfoAgeRatingEnum.A_18_PLUS,
    }
)
METRON_AGE_RATING_MAP: MappingProxyType[Enum, Enum] = MappingProxyType(
    {
        MarvelAgeRatingEnum.ALL_AGES: MetronAgeRatingEnum.EVERYONE,
        MarvelAgeRatingEnum.PG: MetronAgeRatingEnum.TEEN,
        MarvelAgeRatingEnum.PG_PLUS: MetronAgeRatingEnum.TEEN_PLUS,
        MarvelAgeRatingEnum.PARENTAL_ADVISORY: MetronAgeRatingEnum.TEEN_PLUS,
        MarvelAgeRatingEnum.PSR: MetronAgeRatingEnum.TEEN,
        MarvelAgeRatingEnum.PSR_PLUS: MetronAgeRatingEnum.TEEN_PLUS,
        MarvelAgeRatingEnum.A: MetronAgeRatingEnum.EVERYONE,
        MarvelAgeRatingEnum.T_PLUS: MetronAgeRatingEnum.TEEN_PLUS,
        MarvelAgeRatingEnum.T: MetronAgeRatingEnum.TEEN,
        MarvelAgeRatingEnum.EXPLICIT_CONTENT: MetronAgeRatingEnum.EXPLICIT,
        DCAgeRatingEnum.E: MetronAgeRatingEnum.EVERYONE,
        DCAgeRatingEnum.EVERYONE: MetronAgeRatingEnum.EVERYONE,
        DCAgeRatingEnum.T: MetronAgeRatingEnum.TEEN,
        DCAgeRatingEnum.TEEN: MetronAgeRatingEnum.TEEN,
        DCAgeRatingEnum.T_PLUS: MetronAgeRatingEnum.TEEN_PLUS,
        DCAgeRatingEnum.TEEN_PLUS: MetronAgeRatingEnum.TEEN_PLUS,
        DCAgeRatingEnum.M: MetronAgeRatingEnum.MATURE,
        DCAgeRatingEnum.MATURE: MetronAgeRatingEnum.MATURE,
        DCAgeRatingEnum.THIRTEEN_PLUS: MetronAgeRatingEnum.TEEN,
        DCAgeRatingEnum.FIFTEEN_PLUS: MetronAgeRatingEnum.TEEN_PLUS,
        DCAgeRatingEnum.SEVENTEEN_PLUS: MetronAgeRatingEnum.MATURE,
        GenericAgeRatingEnum.PG13: MetronAgeRatingEnum.TEEN,
        GenericAgeRatingEnum.R: MetronAgeRatingEnum.MATURE,
        GenericAgeRatingEnum.X: MetronAgeRatingEnum.ADULT,
        GenericAgeRatingEnum.XXX: MetronAgeRatingEnum.ADULT,
        GenericAgeRatingEnum.ADULT: MetronAgeRatingEnum.ADULT,
        GenericAgeRatingEnum.PORN: MetronAgeRatingEnum.ADULT,
        GenericAgeRatingEnum.PORNOGRAPHY: MetronAgeRatingEnum.ADULT,
        GenericAgeRatingEnum.SEX: MetronAgeRatingEnum.ADULT,
        GenericAgeRatingEnum.SEXUALLY_EXPLICIT: MetronAgeRatingEnum.ADULT,
        GenericAgeRatingEnum.VIOLENT: MetronAgeRatingEnum.EXPLICIT,
        GenericAgeRatingEnum.VIOLENCE: MetronAgeRatingEnum.EXPLICIT,
        ComicInfoAgeRatingEnum.UNKNOWN: MetronAgeRatingEnum.UNKNOWN,
        ComicInfoAgeRatingEnum.PENDING: MetronAgeRatingEnum.UNKNOWN,
        ComicInfoAgeRatingEnum.EVERYONE: MetronAgeRatingEnum.EVERYONE,
        ComicInfoAgeRatingEnum.EARLY_CHILDHOOD: MetronAgeRatingEnum.EVERYONE,
        ComicInfoAgeRatingEnum.E_10_PLUS: MetronAgeRatingEnum.EVERYONE,
        ComicInfoAgeRatingEnum.G: MetronAgeRatingEnum.EVERYONE,
        ComicInfoAgeRatingEnum.KIDS_TO_ADULTS: MetronAgeRatingEnum.EVERYONE,
        ComicInfoAgeRatingEnum.TEEN: MetronAgeRatingEnum.TEEN,
        ComicInfoAgeRatingEnum.PG: MetronAgeRatingEnum.TEEN,
        ComicInfoAgeRatingEnum.MA_15_PLUS: MetronAgeRatingEnum.TEEN_PLUS,
        ComicInfoAgeRatingEnum.M: MetronAgeRatingEnum.MATURE,
        ComicInfoAgeRatingEnum.MA_17_PLUS: MetronAgeRatingEnum.MATURE,
        ComicInfoAgeRatingEnum.R_18_PLUS: MetronAgeRatingEnum.MATURE,
        ComicInfoAgeRatingEnum.X_18_PLUS: MetronAgeRatingEnum.EXPLICIT,
        ComicInfoAgeRatingEnum.A_18_PLUS: MetronAgeRatingEnum.ADULT,
    }
)

AGE_RATING_ENUM_MAP = MappingProxyType(
    {
        **{enum: enum for enum in GenericAgeRatingEnum},
        **{enum: enum for enum in DCAgeRatingEnum},
        **{enum: enum for enum in MarvelAgeRatingEnum},
        **{enum: enum for enum in ComicInfoAgeRatingEnum},
        **{enum: enum for enum in MetronAgeRatingEnum},
    }
)


def _get_key_variations(key: str | Enum) -> set[str]:
    """Get fuzzy lookup key variations for an age rating."""
    value = key.value if isinstance(key, Enum) else key
    value = value.lower()
    spaceless = value.replace(" ", "")
    snake = snakecase(value).replace("_", "")
    return {value, spaceless, snake}


def _build_metron_age_rating_lookup() -> MappingProxyType[str, MetronAgeRatingEnum]:
    """Build a fuzzy lookup map from any age rating string to MetronAgeRatingEnum."""
    lookup: dict[str, MetronAgeRatingEnum] = {}
    for source_enum, metron_enum in METRON_AGE_RATING_MAP.items():
        if not isinstance(metron_enum, MetronAgeRatingEnum):
            continue
        for variation in _get_key_variations(source_enum):
            lookup[variation] = metron_enum
    for metron_enum in MetronAgeRatingEnum:
        for variation in _get_key_variations(metron_enum):
            lookup[variation] = metron_enum
    return MappingProxyType(lookup)


_METRON_AGE_RATING_LOOKUP: MappingProxyType[str, MetronAgeRatingEnum] = (
    _build_metron_age_rating_lookup()
)


def to_metron_age_rating(value: str | Enum) -> MetronAgeRatingEnum | None:
    """
    Convert any age rating string or enum to a MetronAgeRatingEnum.

    Accepts any age rating enum (Marvel, DC, Generic, ComicInfo, Metron)
    or a string representation. Uses fuzzy matching (case-insensitive,
    space-insensitive) for strings.

    Returns None if the value cannot be matched to a known age rating.
    """
    if isinstance(value, MetronAgeRatingEnum):
        return value
    if isinstance(value, Enum):
        result = METRON_AGE_RATING_MAP.get(value)
        if isinstance(result, MetronAgeRatingEnum):
            return result
        return None
    return _METRON_AGE_RATING_LOOKUP.get(value.lower())