Clarify vaginal penetration geometry

This commit is contained in:
2026-06-25 18:29:43 +02:00
parent 7dc4333746
commit e916609de8
2 changed files with 127 additions and 11 deletions
+107
View File
@@ -856,6 +856,40 @@ def _is_oral_text(*parts: Any) -> bool:
)
def _is_vaginal_penetration_text(*parts: Any) -> bool:
text = " ".join(_clean(part).lower() for part in parts if _clean(part))
if not text or _is_outercourse_text(text) or _is_oral_text(text):
return False
if any(term in text for term in ("anal", "double penetration", "double-penetration", "toy-assisted", "strap-on")):
return False
return any(
term in text
for term in (
"vaginal penetration",
"deep vaginal sex",
"explicit penetrative sex",
"penetrative sex",
"penis entering pussy",
"penis thrusts into her pussy",
"penis thrusts into the woman",
"pussy stretched around a penis",
"hardcore vaginal thrusting",
"full-body penetrative sex",
"close-contact vaginal sex",
"missionary position",
"cowgirl position",
"reverse cowgirl position",
"doggy style position",
"standing sex position",
"spooning sex position",
"edge-of-bed position",
"kneeling straddle position",
"lotus sex position",
"bent-over position",
)
)
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:
@@ -1521,6 +1555,74 @@ def _dedupe_oral_detail(detail: str, role_graph: str, hard_item: str = "", axis_
return _join_detail_clauses(clauses)
def _dedupe_penetration_detail(detail: str, role_graph: str, hard_item: str = "", axis_values: Any = None) -> str:
detail = _clean(detail)
if not detail:
return ""
role_lower = _clean(role_graph).lower()
detail = re.sub(
r"\b(?:front-facing|side-profile|rear-view|overhead|mirror-reflected|low-angle|close-up|wide full-body)\s+view of\s+"
r"(?:vaginal penetration with visible genital contact|deep vaginal sex|explicit penetrative sex|penetrative sex|"
r"penis entering pussy|pussy stretched around a penis|hardcore vaginal thrusting|full-body penetrative sex|"
r"close-contact vaginal sex)\b,?\s*",
"",
detail,
flags=re.IGNORECASE,
)
act_terms = (
"vaginal penetration with visible genital contact",
"deep vaginal sex",
"explicit penetrative sex",
"penetrative sex",
"penis entering pussy",
"pussy stretched around a penis",
"hardcore vaginal thrusting",
"full-body penetrative sex",
"close-contact vaginal sex",
"missionary position",
"cowgirl position",
"reverse cowgirl position",
"doggy style position",
"standing sex position",
"spooning sex position",
"edge-of-bed position",
"kneeling straddle position",
"lotus sex position",
"bent-over position",
)
clauses: list[str] = []
for clause in _detail_clauses(detail):
lower = clause.lower()
if any(term in lower for term in act_terms):
continue
if lower in (
"tongues visible while kissing",
"deep kissing",
"mouth close to the ear",
"neck kissing",
"explicit genital contact visible",
"genitals clearly visible",
"anatomically clear penetration",
"pussy and penis visible",
"wetness visible between the thighs",
):
continue
if lower in ("legs spread wide", "thighs open toward the viewer") and any(
term in role_lower for term in ("legs spread wide", "thighs open", "open thighs")
):
continue
if lower == "one body pinned under another" and "lies under" in role_lower:
continue
if lower in ("hips locked tightly together", "hips aligned") and "hips" in role_lower:
continue
if lower in ("hands gripping hips", "hands spreading the thighs") and any(
term in role_lower for term in ("hips", "thighs", "legs")
):
continue
clauses.append(clause)
return _join_detail_clauses(clauses)
def _detail_clauses(detail: str) -> list[str]:
return [part.strip(" ,;") for part in re.split(r",\s*(?:and\s+)?", _clean(detail)) if part.strip(" ,;")]
@@ -1846,6 +1948,7 @@ def _hardcore_action_sentence(
anchor = _hardcore_pose_anchor(role_graph, hard_item, composition, axis_values)
is_outercourse = _is_outercourse_text(role_graph, hard_item, composition, _axis_values_text(axis_values))
is_oral = _is_oral_text(role_graph, hard_item, composition, _axis_values_text(axis_values))
is_penetrative = _is_vaginal_penetration_text(role_graph, hard_item, composition, _axis_values_text(axis_values))
if _is_toy_assisted_double_text(role_graph, hard_item, composition, _axis_values_text(axis_values)):
role_graph = re.sub(
r"\s+while a toy adds (?:the|a) second penetration point\b",
@@ -1864,6 +1967,10 @@ def _hardcore_action_sentence(
anchor = ""
detail = _dedupe_oral_detail(detail, role_graph, hard_item, axis_values)
detail = _limit_detail_for_density(detail, detail_density, False)
elif is_penetrative and role_graph:
anchor = ""
detail = _dedupe_penetration_detail(detail, role_graph, hard_item, axis_values)
detail = _limit_detail_for_density(detail, detail_density, False)
else:
detail = _dedupe_hardcore_detail(detail, anchor) if anchor else detail
if _is_toy_assisted_double_text(role_graph, hard_item, composition, _axis_values_text(axis_values)):