Accept flexible hardcore metadata labels
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import re
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -44,9 +45,32 @@ HARDCORE_ACTION_FAMILY_CHOICES = {
|
|||||||
|
|
||||||
|
|
||||||
def normalize_hardcore_action_family(value: Any, default: str = "") -> str:
|
def normalize_hardcore_action_family(value: Any, default: str = "") -> str:
|
||||||
text = str(value or "").strip().lower()
|
text = re.sub(r"[^a-z0-9]+", "_", str(value or "").strip().lower()).strip("_")
|
||||||
if text == "penetrative":
|
aliases = {
|
||||||
text = ACTION_PENETRATION
|
"penetrative": ACTION_PENETRATION,
|
||||||
|
"penetrative_sex": ACTION_PENETRATION,
|
||||||
|
"penetration_sex": ACTION_PENETRATION,
|
||||||
|
"vaginal": ACTION_PENETRATION,
|
||||||
|
"vaginal_penetration": ACTION_PENETRATION,
|
||||||
|
"double": ACTION_TOY_DOUBLE,
|
||||||
|
"double_penetration": ACTION_TOY_DOUBLE,
|
||||||
|
"toy_double_penetration": ACTION_TOY_DOUBLE,
|
||||||
|
"toy_assisted_double": ACTION_TOY_DOUBLE,
|
||||||
|
"toy_assisted_double_penetration": ACTION_TOY_DOUBLE,
|
||||||
|
"outer_course": ACTION_OUTERCOURSE,
|
||||||
|
"outercourse_sex": ACTION_OUTERCOURSE,
|
||||||
|
"manual": ACTION_FOREPLAY,
|
||||||
|
"manual_stimulation": ACTION_FOREPLAY,
|
||||||
|
"interaction": ACTION_FOREPLAY,
|
||||||
|
"body_worship": ACTION_FOREPLAY,
|
||||||
|
"body_worship_touching": ACTION_FOREPLAY,
|
||||||
|
"foreplay_teasing": ACTION_FOREPLAY,
|
||||||
|
"cumshot": ACTION_CLIMAX,
|
||||||
|
"cumshot_climax": ACTION_CLIMAX,
|
||||||
|
"orgasm_aftermath": ACTION_CLIMAX,
|
||||||
|
"oral_sex": ACTION_ORAL,
|
||||||
|
}
|
||||||
|
text = aliases.get(text, text)
|
||||||
return text if text in HARDCORE_ACTION_FAMILY_CHOICES else default
|
return text if text in HARDCORE_ACTION_FAMILY_CHOICES else default
|
||||||
|
|
||||||
|
|
||||||
@@ -86,7 +110,24 @@ def source_hardcore_action_family(
|
|||||||
inferred = infer_hardcore_action_family(role_graph, hard_item, composition, axis_values)
|
inferred = infer_hardcore_action_family(role_graph, hard_item, composition, axis_values)
|
||||||
if inferred in (ACTION_CLIMAX, ACTION_TOY_DOUBLE):
|
if inferred in (ACTION_CLIMAX, ACTION_TOY_DOUBLE):
|
||||||
return inferred
|
return inferred
|
||||||
family = str(source_family or "").strip().lower()
|
family = re.sub(r"[^a-z0-9]+", "_", str(source_family or "").strip().lower()).strip("_")
|
||||||
|
family = {
|
||||||
|
"penetration": "penetrative",
|
||||||
|
"penetrative_sex": "penetrative",
|
||||||
|
"outer_course": "outercourse",
|
||||||
|
"outercourse_sex": "outercourse",
|
||||||
|
"manual_stimulation": "manual",
|
||||||
|
"foreplay_teasing": "foreplay",
|
||||||
|
"body_worship": "interaction",
|
||||||
|
"body_worship_touching": "interaction",
|
||||||
|
"clothing_position_transitions": "interaction",
|
||||||
|
"dominant_guidance": "interaction",
|
||||||
|
"camera_performance": "interaction",
|
||||||
|
"group_coordination": "interaction",
|
||||||
|
"cumshot": "climax",
|
||||||
|
"cumshot_climax": "climax",
|
||||||
|
"oral_sex": "oral",
|
||||||
|
}.get(family, family)
|
||||||
source_mapping = {
|
source_mapping = {
|
||||||
"penetrative": ACTION_PENETRATION,
|
"penetrative": ACTION_PENETRATION,
|
||||||
"foreplay": ACTION_FOREPLAY,
|
"foreplay": ACTION_FOREPLAY,
|
||||||
|
|||||||
@@ -276,7 +276,36 @@ def hardcore_position_key_choices() -> list[str]:
|
|||||||
|
|
||||||
|
|
||||||
def normalize_hardcore_position_family(value: Any, default: str = "any") -> str:
|
def normalize_hardcore_position_family(value: Any, default: str = "any") -> str:
|
||||||
text = str(value or default).strip()
|
text = re.sub(r"[^a-z0-9]+", "_", str(value or default).strip().lower()).strip("_")
|
||||||
|
aliases = {
|
||||||
|
"penetration": "penetrative",
|
||||||
|
"penetrative_sex": "penetrative",
|
||||||
|
"penetration_sex": "penetrative",
|
||||||
|
"vaginal": "penetrative",
|
||||||
|
"vaginal_penetration": "penetrative",
|
||||||
|
"foreplay_teasing": "foreplay",
|
||||||
|
"body_worship": "interaction",
|
||||||
|
"body_worship_touching": "interaction",
|
||||||
|
"clothing_position_transitions": "interaction",
|
||||||
|
"dominant_guidance": "interaction",
|
||||||
|
"camera_performance": "interaction",
|
||||||
|
"group_coordination": "interaction",
|
||||||
|
"aftercare_cleanup": "interaction",
|
||||||
|
"manual_stimulation": "manual",
|
||||||
|
"oral_sex": "oral",
|
||||||
|
"outer_course": "outercourse",
|
||||||
|
"outercourse_sex": "outercourse",
|
||||||
|
"anal_double_penetration": "anal",
|
||||||
|
"three_some": "threesome",
|
||||||
|
"threesomes": "threesome",
|
||||||
|
"group_sex": "group",
|
||||||
|
"group_sex_orgy": "group",
|
||||||
|
"orgy": "group",
|
||||||
|
"cumshot": "climax",
|
||||||
|
"cumshot_climax": "climax",
|
||||||
|
"orgasm_aftermath": "climax",
|
||||||
|
}
|
||||||
|
text = aliases.get(text, text)
|
||||||
return text if text in HARDCORE_POSITION_FAMILY_CHOICES else default
|
return text if text in HARDCORE_POSITION_FAMILY_CHOICES else default
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ import filter_config # noqa: E402
|
|||||||
import formatter_detail # noqa: E402
|
import formatter_detail # noqa: E402
|
||||||
import formatter_input # noqa: E402
|
import formatter_input # noqa: E402
|
||||||
import formatter_target # noqa: E402
|
import formatter_target # noqa: E402
|
||||||
|
import hardcore_action_metadata # noqa: E402
|
||||||
import hardcore_position_config # noqa: E402
|
import hardcore_position_config # noqa: E402
|
||||||
import __init__ as sxcp_nodes # noqa: E402
|
import __init__ as sxcp_nodes # noqa: E402
|
||||||
import generation_profile_config # noqa: E402
|
import generation_profile_config # noqa: E402
|
||||||
@@ -3741,6 +3742,22 @@ def smoke_hardcore_position_config_policy() -> None:
|
|||||||
)
|
)
|
||||||
_expect("outercourse_only" in hardcore_position_config.hardcore_position_focus_choices(), "Hardcore focus choices lost outercourse_only")
|
_expect("outercourse_only" in hardcore_position_config.hardcore_position_focus_choices(), "Hardcore focus choices lost outercourse_only")
|
||||||
_expect("boobjob" in hardcore_position_config.hardcore_position_key_choices(), "Hardcore position keys lost boobjob")
|
_expect("boobjob" in hardcore_position_config.hardcore_position_key_choices(), "Hardcore position keys lost boobjob")
|
||||||
|
_expect(
|
||||||
|
category_template_metadata.template_action_family({"action_family": "toy double"}) == "toy_double",
|
||||||
|
"Template action-family normalizer should accept spaced aliases",
|
||||||
|
)
|
||||||
|
_expect(
|
||||||
|
category_template_metadata.template_action_family({"action_family": "manual stimulation"}) == "foreplay",
|
||||||
|
"Template action-family normalizer should accept subcategory-style aliases",
|
||||||
|
)
|
||||||
|
_expect(
|
||||||
|
category_template_metadata.template_position_family({"position_family": "penetration"}) == "penetrative",
|
||||||
|
"Template position-family normalizer should accept action-style aliases",
|
||||||
|
)
|
||||||
|
_expect(
|
||||||
|
category_template_metadata.template_position_family({"position_family": "outer-course"}) == "outercourse",
|
||||||
|
"Template position-family normalizer should accept hyphenated aliases",
|
||||||
|
)
|
||||||
|
|
||||||
base = json.loads(
|
base = json.loads(
|
||||||
pb.build_hardcore_position_pool_json(
|
pb.build_hardcore_position_pool_json(
|
||||||
@@ -3876,6 +3893,12 @@ def smoke_hardcore_position_config_policy() -> None:
|
|||||||
_expect(keys == ["doggy"], "Hardcore position key detection changed")
|
_expect(keys == ["doggy"], "Hardcore position key detection changed")
|
||||||
source_family = hardcore_position_config.hardcore_source_position_family({"slug": "manual_stimulation"}, filtered)
|
source_family = hardcore_position_config.hardcore_source_position_family({"slug": "manual_stimulation"}, filtered)
|
||||||
_expect(source_family == "manual", "Hardcore source family lookup changed")
|
_expect(source_family == "manual", "Hardcore source family lookup changed")
|
||||||
|
source_action_family = hardcore_action_metadata.source_hardcore_action_family(
|
||||||
|
"outer-course",
|
||||||
|
"",
|
||||||
|
"generic contact",
|
||||||
|
)
|
||||||
|
_expect(source_action_family == "outercourse", "Source action-family fallback should accept hyphenated source aliases")
|
||||||
item_text, item_name, axis_values, template_metadata = pb._compose_item(
|
item_text, item_name, axis_values, template_metadata = pb._compose_item(
|
||||||
random.Random(42),
|
random.Random(42),
|
||||||
{},
|
{},
|
||||||
|
|||||||
Reference in New Issue
Block a user