Promote anal hardcore action routing
This commit is contained in:
@@ -26,6 +26,7 @@ except ImportError: # Allows local smoke tests with `python -c`.
|
||||
|
||||
|
||||
ACTION_CLIMAX = "climax"
|
||||
ACTION_ANAL = "anal"
|
||||
ACTION_FOREPLAY = "foreplay"
|
||||
ACTION_MANUAL = "manual"
|
||||
ACTION_OUTERCOURSE = "outercourse"
|
||||
@@ -36,6 +37,7 @@ ACTION_DEFAULT = "default"
|
||||
|
||||
HARDCORE_ACTION_FAMILY_CHOICES = {
|
||||
ACTION_CLIMAX,
|
||||
ACTION_ANAL,
|
||||
ACTION_FOREPLAY,
|
||||
ACTION_MANUAL,
|
||||
ACTION_OUTERCOURSE,
|
||||
@@ -59,6 +61,9 @@ def normalize_hardcore_action_family(value: Any, default: str = "") -> str:
|
||||
"toy_double_penetration": ACTION_TOY_DOUBLE,
|
||||
"toy_assisted_double": ACTION_TOY_DOUBLE,
|
||||
"toy_assisted_double_penetration": ACTION_TOY_DOUBLE,
|
||||
"anal": ACTION_ANAL,
|
||||
"anal_sex": ACTION_ANAL,
|
||||
"anal_penetration": ACTION_ANAL,
|
||||
"outer_course": ACTION_OUTERCOURSE,
|
||||
"outercourse_sex": ACTION_OUTERCOURSE,
|
||||
"manual": ACTION_MANUAL,
|
||||
@@ -132,6 +137,7 @@ def source_hardcore_action_family(
|
||||
}.get(family, family)
|
||||
source_mapping = {
|
||||
"penetrative": ACTION_PENETRATION,
|
||||
"anal": ACTION_ANAL,
|
||||
"foreplay": ACTION_FOREPLAY,
|
||||
"interaction": ACTION_FOREPLAY,
|
||||
"manual": ACTION_MANUAL,
|
||||
@@ -139,6 +145,4 @@ def source_hardcore_action_family(
|
||||
"outercourse": ACTION_OUTERCOURSE,
|
||||
"climax": ACTION_CLIMAX,
|
||||
}
|
||||
if family == "anal":
|
||||
return ACTION_DEFAULT
|
||||
return source_mapping.get(family, inferred)
|
||||
|
||||
@@ -248,14 +248,15 @@ def is_vaginal_penetration_text(*parts: Any) -> bool:
|
||||
|
||||
def is_toy_assisted_double_text(*parts: Any) -> bool:
|
||||
text = " ".join(_clean(part).lower() for part in parts if _clean(part))
|
||||
if "toy" not in text:
|
||||
return False
|
||||
return any(
|
||||
token in text
|
||||
for token in (
|
||||
"double penetration",
|
||||
"double-penetration",
|
||||
"front-and-back double",
|
||||
"vaginal and anal penetration",
|
||||
"pussy and ass filled",
|
||||
"one penis in pussy and one penis in ass",
|
||||
"second penetration point",
|
||||
"second point of contact",
|
||||
"second contact",
|
||||
|
||||
@@ -12,6 +12,7 @@ try:
|
||||
normalize_hardcore_detail_density,
|
||||
)
|
||||
from .hardcore_action_metadata import (
|
||||
ACTION_ANAL,
|
||||
ACTION_CLIMAX,
|
||||
ACTION_FOREPLAY,
|
||||
ACTION_MANUAL,
|
||||
@@ -42,6 +43,7 @@ except ImportError: # Allows local smoke tests with `python -c`.
|
||||
normalize_hardcore_detail_density,
|
||||
)
|
||||
from hardcore_action_metadata import (
|
||||
ACTION_ANAL,
|
||||
ACTION_CLIMAX,
|
||||
ACTION_FOREPLAY,
|
||||
ACTION_MANUAL,
|
||||
@@ -156,7 +158,7 @@ def action_detail_for_family(
|
||||
if family == ACTION_ORAL and role_graph:
|
||||
detail = dedupe_oral_detail(detail, role_graph, hard_item, axis_values)
|
||||
return "", limit_detail_for_density(detail, detail_density, False)
|
||||
if family == ACTION_PENETRATION and role_graph:
|
||||
if family in (ACTION_ANAL, ACTION_PENETRATION) and role_graph:
|
||||
detail = dedupe_penetration_detail(detail, role_graph, hard_item, axis_values)
|
||||
return "", limit_detail_for_density(detail, detail_density, False)
|
||||
|
||||
|
||||
@@ -68,21 +68,23 @@ def hardcore_pose_anchor(role_graph: str, hard_item: str, composition: str = "",
|
||||
return "footjob outercourse pose"
|
||||
return "non-penetrative outercourse pose"
|
||||
if is_toy_assisted_double_text(role_graph, hard_item, composition, axis_values_text(axis_values)):
|
||||
prefix = "toy-assisted " if ("toy" in text or "strap-on" in text) else ""
|
||||
front_back = "front-and-back" in text or "from the front" in text or "pussy and ass" in text
|
||||
if "face-down ass-up" in text or "face-down" in text:
|
||||
return "toy-assisted face-down rear-entry double-penetration pose"
|
||||
return f"{prefix}face-down rear-entry double-penetration pose"
|
||||
if "doggy style" in text or "doggy-style" in text or "all fours" in text or "rear-entry" in text:
|
||||
return "toy-assisted rear-entry double-penetration pose"
|
||||
return f"{prefix}rear-entry double-penetration pose"
|
||||
if "bent-over" in text or "bent forward" in text:
|
||||
return "toy-assisted bent-over double-penetration pose"
|
||||
return f"{prefix}bent-over double-penetration pose"
|
||||
if "spooning anal" in text or "side-lying anal" in text or "side-lying" in text:
|
||||
return "toy-assisted side-lying double-penetration pose"
|
||||
return f"{prefix}side-lying double-penetration pose"
|
||||
if "edge-supported" in text or "bed-edge" in text or "edge-of-bed" in text:
|
||||
return "toy-assisted edge-supported double-penetration pose"
|
||||
return f"{prefix}edge-supported front-and-back double-penetration pose" if front_back else f"{prefix}edge-supported double-penetration pose"
|
||||
if "standing anal" in text or "standing supported" in text or "standing" in text:
|
||||
return "toy-assisted standing double-penetration pose"
|
||||
return f"{prefix}standing front-and-back double-penetration pose" if front_back else f"{prefix}standing double-penetration pose"
|
||||
if "kneeling anal" in text or "kneeling" in text:
|
||||
return "toy-assisted kneeling rear-entry double-penetration pose"
|
||||
return "toy-assisted rear-entry double-penetration pose"
|
||||
return f"{prefix}kneeling front-and-back double-penetration pose" if front_back else f"{prefix}kneeling rear-entry double-penetration pose"
|
||||
return f"{prefix}front-and-back double-penetration pose" if front_back else f"{prefix}rear-entry double-penetration pose"
|
||||
if "double penetration" in text or "vaginal and anal penetration" in text or "front-and-back" in text:
|
||||
if "face-down ass-up" in text:
|
||||
return "face-down rear-entry double-penetration pose"
|
||||
|
||||
@@ -47,6 +47,7 @@ SDXL_DEFAULT_NEGATIVE = (
|
||||
)
|
||||
|
||||
SDXL_ACTION_FAMILY_TAGS = {
|
||||
"anal": ("anal sex",),
|
||||
"foreplay": ("foreplay", "body contact"),
|
||||
"manual": ("manual stimulation",),
|
||||
"outercourse": ("outercourse", "non-penetrative sex"),
|
||||
|
||||
@@ -22,6 +22,7 @@ except ImportError: # Allows local smoke tests with `python -c`.
|
||||
PROMPT_FIELD_LABELS = input_policy.prompt_field_labels()
|
||||
|
||||
INCOMPATIBLE_ROUTE_TAGS = {
|
||||
"action:anal": ("oral sex", "outercourse", "manual stimulation"),
|
||||
"action:penetration": ("oral sex", "outercourse", "anal sex", "manual stimulation"),
|
||||
"action:oral": ("penetrative sex", "penetration", "anal sex", "outercourse"),
|
||||
"action:outercourse": ("penetrative sex", "penetration", "oral sex", "anal sex", "manual stimulation"),
|
||||
|
||||
@@ -295,7 +295,7 @@ HARDCORE_ROUTE_CASES = (
|
||||
"subcategory": "Anal and double penetration",
|
||||
"focus": "anal_only",
|
||||
"family": "anal",
|
||||
"expected_route": {"position_family": "anal"},
|
||||
"expected_route": {"action_family": "anal", "position_family": "anal"},
|
||||
"expected_terms": {
|
||||
"krea": ("anal",),
|
||||
"sdxl": ("anal sex",),
|
||||
|
||||
@@ -4909,6 +4909,10 @@ def smoke_hardcore_position_config_policy() -> None:
|
||||
category_template_metadata.template_action_family({"action_family": "manual stimulation"}) == "manual",
|
||||
"Template action-family normalizer should accept subcategory-style aliases",
|
||||
)
|
||||
_expect(
|
||||
category_template_metadata.template_action_family({"action_family": "anal sex"}) == "anal",
|
||||
"Template action-family normalizer should accept anal aliases",
|
||||
)
|
||||
_expect(
|
||||
category_template_metadata.template_position_family({"position_family": "penetration"}) == "penetrative",
|
||||
"Template position-family normalizer should accept action-style aliases",
|
||||
@@ -5520,6 +5524,7 @@ def smoke_hardcore_category_routes() -> None:
|
||||
("hardcore_penetration", "Penetrative sex", "penetration_only", "penetrative", {"penetration", "default"}, "penetrative sex", "penetrative action"),
|
||||
("hardcore_oral", "Oral sex", "oral_only", "oral", {"oral"}, "oral sex", "oral action"),
|
||||
("hardcore_manual", "Manual stimulation", "manual_only", "manual", {"manual"}, "manual stimulation", "manual action"),
|
||||
("hardcore_anal", "Anal and double penetration", "anal_only", "anal", {"anal", "toy_double"}, "anal sex", "anal action"),
|
||||
("hardcore_outercourse", "Outercourse and genital teasing", "outercourse_only", "outercourse", {"outercourse"}, "outercourse", "non-penetrative action"),
|
||||
("hardcore_foreplay", "Foreplay and teasing", "foreplay_only", "foreplay", {"foreplay"}, "foreplay", "foreplay action"),
|
||||
("hardcore_aftercare", "Aftercare and cleanup", "interaction_only", "interaction", {"foreplay"}, "interaction", "interaction beat"),
|
||||
@@ -6708,6 +6713,7 @@ def smoke_pov_anal_position_routes() -> None:
|
||||
_expect_pair(pair, name)
|
||||
hard_row = pair.get("hardcore_row") or {}
|
||||
_expect(hard_row.get("position_family") == "anal", f"{name} position_family should be anal")
|
||||
_expect(hard_row.get("action_family") == "anal", f"{name} action_family should be anal")
|
||||
_expect(position_key in (hard_row.get("position_keys") or []), f"{name} lost position key {position_key!r}")
|
||||
role_graph = _expect_text(f"{name}.source_role_graph", hard_row.get("source_role_graph"), 40).lower()
|
||||
for term in role_terms:
|
||||
@@ -6752,6 +6758,7 @@ def smoke_double_front_back_route() -> None:
|
||||
_expect_pair(pair, "double_front_back_route")
|
||||
hard_row = pair.get("hardcore_row") or {}
|
||||
_expect(hard_row.get("position_family") == "anal", "double route position_family should be anal")
|
||||
_expect(hard_row.get("action_family") == "toy_double", "double route action_family should stay toy_double")
|
||||
_expect("front_back" in (hard_row.get("position_keys") or []), "double route lost front_back key")
|
||||
role_graph = _expect_text("double_front_back_route.source_role_graph", hard_row.get("source_role_graph"), 40).lower()
|
||||
_expect("second penetration point from the front" in role_graph, f"double route role graph lost front/back placement: {role_graph}")
|
||||
|
||||
Reference in New Issue
Block a user