Expand hardcore interaction pools
This commit is contained in:
+265
-6
@@ -300,6 +300,8 @@ HARDCORE_POSITION_FAMILY_CHOICES = [
|
||||
"any",
|
||||
"penetrative",
|
||||
"foreplay",
|
||||
"interaction",
|
||||
"manual",
|
||||
"oral",
|
||||
"outercourse",
|
||||
"anal",
|
||||
@@ -311,6 +313,8 @@ HARDCORE_POSITION_FOCUS_CHOICES = [
|
||||
"keep_pool",
|
||||
"penetration_only",
|
||||
"foreplay_only",
|
||||
"interaction_only",
|
||||
"manual_only",
|
||||
"oral_only",
|
||||
"outercourse_only",
|
||||
"anal_only",
|
||||
@@ -341,6 +345,22 @@ HARDCORE_POSITION_KEY_CHOICES = [
|
||||
"breast_touch",
|
||||
"face_touch",
|
||||
"undressing",
|
||||
"body_worship",
|
||||
"nipple_play",
|
||||
"ass_grab",
|
||||
"thigh_kissing",
|
||||
"hair_holding",
|
||||
"wrist_pinning",
|
||||
"dirty_talk",
|
||||
"position_transition",
|
||||
"guided_positioning",
|
||||
"camera_showing",
|
||||
"watching",
|
||||
"aftercare",
|
||||
"cleanup",
|
||||
"fingering",
|
||||
"clit_rubbing",
|
||||
"mutual_masturbation",
|
||||
"boobjob",
|
||||
"testicle_sucking",
|
||||
"penis_licking",
|
||||
@@ -353,17 +373,34 @@ HARDCORE_POSITION_FAMILY_SUBCATEGORIES = {
|
||||
"any": [
|
||||
"penetrative_sex",
|
||||
"foreplay_teasing",
|
||||
"body_worship_touching",
|
||||
"clothing_position_transitions",
|
||||
"dominant_guidance",
|
||||
"camera_performance",
|
||||
"manual_stimulation",
|
||||
"oral_sex",
|
||||
"outercourse_sex",
|
||||
"anal_double_penetration",
|
||||
"threesomes",
|
||||
"group_coordination",
|
||||
"group_sex_orgy",
|
||||
"cumshot_climax",
|
||||
"aftercare_cleanup",
|
||||
],
|
||||
"penetrative": ["penetrative_sex"],
|
||||
"foreplay": ["foreplay_teasing"],
|
||||
"interaction": [
|
||||
"foreplay_teasing",
|
||||
"body_worship_touching",
|
||||
"clothing_position_transitions",
|
||||
"dominant_guidance",
|
||||
"camera_performance",
|
||||
"group_coordination",
|
||||
"aftercare_cleanup",
|
||||
],
|
||||
"manual": ["manual_stimulation"],
|
||||
"oral": ["oral_sex"],
|
||||
"outercourse": ["outercourse_sex"],
|
||||
"outercourse": ["outercourse_sex", "manual_stimulation"],
|
||||
"anal": ["anal_double_penetration"],
|
||||
"climax": ["cumshot_climax"],
|
||||
"threesome": ["threesomes"],
|
||||
@@ -392,6 +429,22 @@ HARDCORE_POSITION_KEY_MATCHES = {
|
||||
"breast_touch": ("breast", "breasts", "nipple", "cupping breasts", "touching breasts"),
|
||||
"face_touch": ("face", "cheek", "jaw", "chin", "hand on the cheek", "fingers under the chin"),
|
||||
"undressing": ("undressing", "removing clothing", "removing clothes", "pulling clothing", "sliding straps", "unbuttoning"),
|
||||
"body_worship": ("body worship", "worship", "kissing down", "mouth on skin", "kissing the body"),
|
||||
"nipple_play": ("nipple", "nipples", "licking nipples", "sucking nipples", "nipple play"),
|
||||
"ass_grab": ("ass grab", "ass-grab", "ass grabbing", "hand on the ass", "squeezing the ass"),
|
||||
"thigh_kissing": ("thigh kiss", "thigh kissing", "kissing thighs", "mouth on inner thighs"),
|
||||
"hair_holding": ("hair holding", "hair held", "holding hair", "hair pulled back"),
|
||||
"wrist_pinning": ("wrist", "wrists", "pinning wrists", "wrists pinned", "hands pinned"),
|
||||
"dirty_talk": ("dirty talk", "whispering", "mouth near the ear", "telling", "verbal teasing"),
|
||||
"position_transition": ("transition", "turning around", "pulling onto the bed", "moving into position", "position change"),
|
||||
"guided_positioning": ("guiding", "guided", "guides", "lifting legs", "spreading thighs", "pulling hips", "turning the body"),
|
||||
"camera_showing": ("camera", "showing to camera", "presenting to camera", "spread open for camera", "creator-shot"),
|
||||
"watching": ("watching", "voyeur", "waiting turn", "partner watches", "onlooker"),
|
||||
"aftercare": ("aftercare", "cuddling", "kissing after", "holding close", "post-sex"),
|
||||
"cleanup": ("cleanup", "wiping", "cleaning", "towel", "wet cloth"),
|
||||
"fingering": ("fingering", "fingers inside", "fingers in pussy", "finger stimulation"),
|
||||
"clit_rubbing": ("clit", "clitoris", "clit rubbing", "rubbing the clit", "fingers on clit"),
|
||||
"mutual_masturbation": ("mutual masturbation", "both touching themselves", "masturbating together", "hands on their own bodies"),
|
||||
"boobjob": ("boobjob", "titjob", "breast-sex", "breast sex"),
|
||||
"testicle_sucking": ("testicle", "balls-licking", "balls licking", "balls and mouth"),
|
||||
"penis_licking": ("penis-licking", "penis licking", "tongue along", "tongue licking"),
|
||||
@@ -400,7 +453,23 @@ HARDCORE_POSITION_KEY_MATCHES = {
|
||||
"open_thighs": ("thighs open", "legs spread", "open thighs", "legs open", "reclining with thighs open"),
|
||||
"front_back": ("front-and-back", "front and back", "one behind and one in front", "between two partners"),
|
||||
}
|
||||
HARDCORE_POSITION_AXIS_KEYS = {"position", "body_position", "body_arrangement", "arrangement"}
|
||||
HARDCORE_POSITION_AXIS_KEYS = {
|
||||
"position",
|
||||
"body_position",
|
||||
"body_arrangement",
|
||||
"arrangement",
|
||||
"tease_act",
|
||||
"touch_detail",
|
||||
"manual_act",
|
||||
"manual_detail",
|
||||
"worship_act",
|
||||
"transition_act",
|
||||
"control_act",
|
||||
"performance_act",
|
||||
"coordination_act",
|
||||
"aftercare_act",
|
||||
"cleanup_detail",
|
||||
}
|
||||
CAMERA_ORBIT_FRAMING_CHOICES = [
|
||||
"from_zoom",
|
||||
"wide",
|
||||
@@ -2347,6 +2416,8 @@ def _empty_hardcore_position_config() -> dict[str, Any]:
|
||||
"allow_double": True,
|
||||
"allow_penetration": True,
|
||||
"allow_foreplay": True,
|
||||
"allow_interaction": True,
|
||||
"allow_manual": True,
|
||||
"allow_oral": True,
|
||||
"allow_outercourse": True,
|
||||
"allow_anal": True,
|
||||
@@ -2376,6 +2447,8 @@ def _parse_hardcore_position_config(value: str | dict[str, Any] | None) -> dict[
|
||||
"allow_double",
|
||||
"allow_penetration",
|
||||
"allow_foreplay",
|
||||
"allow_interaction",
|
||||
"allow_manual",
|
||||
"allow_oral",
|
||||
"allow_outercourse",
|
||||
"allow_anal",
|
||||
@@ -2401,6 +2474,8 @@ def _hardcore_position_summary(config: dict[str, Any]) -> str:
|
||||
("allow_double", "double"),
|
||||
("allow_penetration", "penetration"),
|
||||
("allow_foreplay", "foreplay"),
|
||||
("allow_interaction", "interaction"),
|
||||
("allow_manual", "manual"),
|
||||
("allow_oral", "oral"),
|
||||
("allow_outercourse", "outercourse"),
|
||||
("allow_anal", "anal"),
|
||||
@@ -2446,6 +2521,8 @@ def build_hardcore_action_filter_json(
|
||||
allow_double: bool = False,
|
||||
allow_penetration: bool = True,
|
||||
allow_foreplay: bool = True,
|
||||
allow_interaction: bool = True,
|
||||
allow_manual: bool = True,
|
||||
allow_oral: bool = True,
|
||||
allow_outercourse: bool = True,
|
||||
allow_anal: bool = True,
|
||||
@@ -2457,6 +2534,8 @@ def build_hardcore_action_filter_json(
|
||||
focus_family = {
|
||||
"penetration_only": "penetrative",
|
||||
"foreplay_only": "foreplay",
|
||||
"interaction_only": "interaction",
|
||||
"manual_only": "manual",
|
||||
"oral_only": "oral",
|
||||
"outercourse_only": "outercourse",
|
||||
"anal_only": "anal",
|
||||
@@ -2470,6 +2549,8 @@ def build_hardcore_action_filter_json(
|
||||
config["allow_double"] = bool(allow_double)
|
||||
config["allow_penetration"] = bool(allow_penetration)
|
||||
config["allow_foreplay"] = bool(allow_foreplay)
|
||||
config["allow_interaction"] = bool(allow_interaction)
|
||||
config["allow_manual"] = bool(allow_manual)
|
||||
config["allow_oral"] = bool(allow_oral)
|
||||
config["allow_outercourse"] = bool(allow_outercourse)
|
||||
config["allow_anal"] = bool(allow_anal)
|
||||
@@ -2481,6 +2562,8 @@ def build_hardcore_action_filter_json(
|
||||
for enabled, family in (
|
||||
(config["allow_penetration"], "penetrative"),
|
||||
(config["allow_foreplay"], "foreplay"),
|
||||
(config["allow_interaction"], "interaction"),
|
||||
(config["allow_manual"], "manual"),
|
||||
(config["allow_oral"], "oral"),
|
||||
(config["allow_outercourse"], "outercourse"),
|
||||
(config["allow_anal"], "anal"),
|
||||
@@ -2493,6 +2576,12 @@ def build_hardcore_action_filter_json(
|
||||
|
||||
if focus == "foreplay_only":
|
||||
config["allow_foreplay"] = True
|
||||
config["allow_interaction"] = True
|
||||
elif focus == "interaction_only":
|
||||
config["allow_interaction"] = True
|
||||
config["allow_foreplay"] = True
|
||||
elif focus == "manual_only":
|
||||
config["allow_manual"] = True
|
||||
elif focus == "oral_only":
|
||||
config["allow_oral"] = True
|
||||
config["allow_penetration"] = False
|
||||
@@ -2530,6 +2619,20 @@ def _hardcore_allowed_subcategory_slugs(config: dict[str, Any]) -> set[str]:
|
||||
allowed.difference_update({"penetrative_sex", "anal_double_penetration", "threesomes", "group_sex_orgy"})
|
||||
if not config.get("allow_foreplay", True):
|
||||
allowed.discard("foreplay_teasing")
|
||||
if not config.get("allow_interaction", True):
|
||||
allowed.difference_update(
|
||||
{
|
||||
"foreplay_teasing",
|
||||
"body_worship_touching",
|
||||
"clothing_position_transitions",
|
||||
"dominant_guidance",
|
||||
"camera_performance",
|
||||
"group_coordination",
|
||||
"aftercare_cleanup",
|
||||
}
|
||||
)
|
||||
if not config.get("allow_manual", True):
|
||||
allowed.discard("manual_stimulation")
|
||||
if not config.get("allow_oral", True):
|
||||
allowed.discard("oral_sex")
|
||||
if not config.get("allow_outercourse", True):
|
||||
@@ -2582,7 +2685,7 @@ def _hardcore_text_blocked_by_action(text: str, axis_name: str, config: dict[str
|
||||
return True
|
||||
if not config.get("allow_anal", True) and (
|
||||
axis_name == "anal_act"
|
||||
or any(term in text for term in (" anal", "ass", "rear-entry anal"))
|
||||
or any(term in text for term in (" anal", "anal sex", "anal penetration", "anus", "rear-entry anal", "penis entering ass", "thrusts into her ass", "thrusts into his ass"))
|
||||
):
|
||||
return True
|
||||
if not config.get("allow_oral", True) and (
|
||||
@@ -2626,6 +2729,68 @@ def _hardcore_text_blocked_by_action(text: str, axis_name: str, config: dict[str
|
||||
)
|
||||
):
|
||||
return True
|
||||
if not config.get("allow_interaction", True) and (
|
||||
axis_name
|
||||
in (
|
||||
"tease_act",
|
||||
"touch_detail",
|
||||
"clothing_detail",
|
||||
"foreplay_detail",
|
||||
"face_detail",
|
||||
"body_contact",
|
||||
"mood_detail",
|
||||
"worship_act",
|
||||
"transition_act",
|
||||
"control_act",
|
||||
"performance_act",
|
||||
"coordination_act",
|
||||
"aftercare_act",
|
||||
"cleanup_detail",
|
||||
)
|
||||
or any(
|
||||
term in text
|
||||
for term in (
|
||||
"kiss",
|
||||
"kissing",
|
||||
"caress",
|
||||
"body worship",
|
||||
"nipple",
|
||||
"ass grab",
|
||||
"thigh",
|
||||
"hair holding",
|
||||
"wrists",
|
||||
"dirty talk",
|
||||
"whispering",
|
||||
"undressing",
|
||||
"position transition",
|
||||
"guided",
|
||||
"camera",
|
||||
"watching",
|
||||
"aftercare",
|
||||
"cleanup",
|
||||
"wiping",
|
||||
)
|
||||
)
|
||||
):
|
||||
return True
|
||||
if not config.get("allow_manual", True) and (
|
||||
axis_name in ("manual_act", "manual_detail")
|
||||
or any(
|
||||
term in text
|
||||
for term in (
|
||||
"fingering",
|
||||
"fingers inside",
|
||||
"clit",
|
||||
"clitoris",
|
||||
"manual stimulation",
|
||||
"mutual masturbation",
|
||||
"masturbating together",
|
||||
"fingers on pussy",
|
||||
"fingers on clit",
|
||||
)
|
||||
)
|
||||
):
|
||||
return True
|
||||
if not config.get("allow_climax", True) and (
|
||||
axis_name in ("climax_act", "climax_hint", "climax_detail", "fluid_detail", "fluid_location")
|
||||
or any(term in text for term in ("climax", "cum", "semen", "ejaculat", "creampie", "post-orgasm", "post-penetration"))
|
||||
@@ -6067,6 +6232,74 @@ def _role_graph(
|
||||
f"hands caressing skin while clothing is pulled aside."
|
||||
)
|
||||
|
||||
def interaction_text() -> str:
|
||||
return " ".join(
|
||||
str(part or "").lower()
|
||||
for part in (
|
||||
item_text,
|
||||
*((item_axis_values or {}).values()),
|
||||
)
|
||||
)
|
||||
|
||||
def manual_position_graph(primary: str, partner: str = "") -> str:
|
||||
text = interaction_text()
|
||||
if not partner:
|
||||
if "mutual" in text:
|
||||
return f"{primary} faces the camera with thighs open, both hands on her body for solo mutual-style masturbation framing."
|
||||
return f"{primary} reclines with thighs open, one hand between her legs and fingers visibly stimulating her pussy."
|
||||
if "mutual" in text:
|
||||
return f"{primary} and {partner} sit close facing each other, both touching themselves while keeping hands, faces, and bodies visible."
|
||||
if "clit" in text or "clitoris" in text:
|
||||
return f"{primary} reclines with thighs open while {partner}'s hand is between her legs, fingers rubbing her clit as her hips tilt toward the touch."
|
||||
if "toy" in text or "vibrator" in text:
|
||||
return f"{primary} reclines with thighs open while {partner} holds a vibrator or toy against her clit, one hand keeping her thigh open."
|
||||
return f"{primary} reclines with thighs open while {partner}'s hand is between her legs, fingers visibly stimulating her pussy."
|
||||
|
||||
def interaction_position_graph(primary: str, partner: str, third: str = "") -> str:
|
||||
text = interaction_text()
|
||||
if "aftercare" in slug or any(term in text for term in ("aftercare", "cleanup", "wiping", "towel", "post-sex", "cuddle")):
|
||||
if "cleanup" in text or "wiping" in text or "towel" in text:
|
||||
return f"{primary} reclines after sex while {partner} kneels close and wipes her skin with a towel, hands and relaxed body contact visible."
|
||||
return f"{primary} and {partner} lie close together after sex, bodies relaxed and hands resting on skin in a post-sex cuddle."
|
||||
if "camera_performance" in slug or any(term in text for term in ("camera", "presenting", "showing", "viewer", "creator-shot")):
|
||||
if third:
|
||||
return f"{primary} faces the camera while {partner} and {third} hold and present her body, hands framing the exposed skin for the viewer."
|
||||
return f"{primary} faces the camera and presents her body while {partner}'s hands hold her hips or thighs open for a clear creator-shot reveal."
|
||||
if "body_worship" in slug or any(term in text for term in ("body worship", "nipple", "thigh", "mouth on skin", "kissing down", "ass grabbing")):
|
||||
if "ass" in text:
|
||||
return f"{primary} stands or kneels with hips angled back while {partner}'s hands grip her ass, fingers pressing into skin."
|
||||
if "thigh" in text:
|
||||
return f"{primary} reclines with thighs open while {partner} kneels close and kisses along her inner thighs, hands holding her legs in place."
|
||||
if "nipple" in text or "breast" in text:
|
||||
return f"{primary} arches toward {partner} while {partner}'s mouth is on her breast and one hand cups or squeezes the other breast."
|
||||
return f"{primary} reclines or leans back while {partner} kisses down her body, hands tracing breasts, waist, hips, and thighs."
|
||||
if "clothing_position" in slug or any(term in text for term in ("transition", "turning", "pulling onto", "lifting", "guided backward", "clothing", "garment")):
|
||||
if "turn" in text or "rear-facing" in text:
|
||||
return f"{partner}'s hands turn {primary} around by the hips, clothing partly moved aside as her body rotates into the next pose."
|
||||
if "legs" in text or "thigh" in text:
|
||||
return f"{primary} lies back while {partner} lifts and spreads her legs into position, hands and clothing movement clearly visible."
|
||||
return f"{primary} and {partner} are mid-transition, with {partner}'s hands moving clothing aside and guiding {primary}'s hips toward the next pose."
|
||||
if "dominant" in slug or any(term in text for term in ("hair", "wrist", "wrists", "jaw", "chin", "guided", "dominant", "control", "dirty talk", "whisper", "mouth near the ear", "verbal teasing")):
|
||||
if "dirty talk" in text or "whisper" in text or "mouth near the ear" in text or "verbal teasing" in text:
|
||||
return f"{partner} leans close to {primary}'s ear for dirty talk while holding her waist and keeping their bodies pressed close."
|
||||
if "wrist" in text or "wrists" in text:
|
||||
return f"{primary} lies back while {partner} pins her wrists above her head, both bodies close and the consensual control gesture clearly visible."
|
||||
if "hair" in text:
|
||||
return f"{partner} holds {primary}'s hair back while guiding her body closer, face and hair-hold gesture visible."
|
||||
if "thigh" in text or "spread" in text:
|
||||
return f"{primary} reclines with thighs open while {partner}'s hands spread her legs and hold the position for the camera."
|
||||
return f"{partner} guides {primary}'s body with hands on her jaw, waist, and hips, keeping the consensual control gesture readable."
|
||||
return foreplay_position_graph(primary, partner)
|
||||
|
||||
def group_coordination_graph(primary: str, partner: str, third: str) -> str:
|
||||
observer = third or any_person({primary, partner})
|
||||
text = interaction_text()
|
||||
if "camera" in text or "hold" in text or "present" in text:
|
||||
return f"{primary} is centered while {partner} and {observer} hold and present the body for the camera, each role clearly visible."
|
||||
if "watch" in text or "waiting" in text:
|
||||
return f"{primary} is centered while {partner} touches her body and {observer} watches close beside them, hands and faces readable."
|
||||
return f"{primary} is centered while {partner} touches her body and {observer} stays close as the watching or guiding partner."
|
||||
|
||||
def mentions_ass(text: str) -> bool:
|
||||
return bool(
|
||||
re.search(
|
||||
@@ -6346,6 +6579,10 @@ def _role_graph(
|
||||
if people_count == 1:
|
||||
solo = people[0]
|
||||
if women_count == 1:
|
||||
if "manual_stimulation" in slug:
|
||||
return manual_position_graph(solo)
|
||||
if "camera_performance" in slug:
|
||||
return f"{solo} faces the camera and presents her body with hands framing the exposed skin in a solo creator-shot pose."
|
||||
if "cumshot" in slug or "climax" in slug:
|
||||
return f"{solo} is shown in a solo explicit orgasm pose with thighs open, one hand on her body, and visible arousal on skin and sheets."
|
||||
return f"{solo} is shown in a solo explicit adult pose with self-touch, open body framing, and direct camera awareness."
|
||||
@@ -6357,7 +6594,16 @@ def _role_graph(
|
||||
a, b = _pick_distinct(rng, women, 2)
|
||||
c = any_woman({a, b}) if len(women) >= 3 else ""
|
||||
used = {a, b}
|
||||
if "foreplay" in slug:
|
||||
if "manual_stimulation" in slug:
|
||||
graph = manual_position_graph(a, b)
|
||||
elif "group_coordination" in slug and c:
|
||||
graph = group_coordination_graph(a, b, c)
|
||||
used.add(c)
|
||||
elif any(token in slug for token in ("foreplay", "body_worship", "clothing_position", "dominant_guidance", "camera_performance", "aftercare")):
|
||||
graph = interaction_position_graph(a, b, c)
|
||||
if c and "camera_performance" in slug:
|
||||
used.add(c)
|
||||
elif "foreplay" in slug:
|
||||
graph = foreplay_position_graph(a, b)
|
||||
elif "outercourse" in slug:
|
||||
graph = f"{a} kneels close to {b}'s body and uses mouth, hands, breasts, or feet for explicit non-penetrative contact."
|
||||
@@ -6379,7 +6625,14 @@ def _role_graph(
|
||||
a, b = _pick_distinct(rng, men, 2)
|
||||
c = any_man({a, b}) if len(men) >= 3 else ""
|
||||
used = {a, b}
|
||||
if "foreplay" in slug:
|
||||
if "manual_stimulation" in slug:
|
||||
graph = f"{a} and {b} sit or recline close together with hands visibly stimulating bodies in a manual sex setup."
|
||||
elif "group_coordination" in slug and c:
|
||||
graph = group_coordination_graph(a, b, c)
|
||||
used.add(c)
|
||||
elif any(token in slug for token in ("foreplay", "body_worship", "clothing_position", "dominant_guidance", "camera_performance", "aftercare")):
|
||||
graph = f"{a} and {b} press close together, kissing and caressing skin while clothing is pulled aside."
|
||||
elif "foreplay" in slug:
|
||||
graph = f"{a} and {b} press close together, kissing and caressing skin while clothing is pulled aside."
|
||||
elif "outercourse" in slug:
|
||||
graph = f"{a} and {b} keep explicit non-penetrative penis contact visible with hands, mouth, or feet."
|
||||
@@ -6401,7 +6654,13 @@ def _role_graph(
|
||||
woman = any_woman()
|
||||
man = any_man()
|
||||
third = any_person({woman, man}) if people_count >= 3 else ""
|
||||
if "foreplay" in slug:
|
||||
if "manual_stimulation" in slug:
|
||||
graph = manual_position_graph(woman, man)
|
||||
elif "group_coordination" in slug:
|
||||
graph = group_coordination_graph(woman, man, third)
|
||||
elif any(token in slug for token in ("foreplay", "body_worship", "clothing_position", "dominant_guidance", "camera_performance", "aftercare")):
|
||||
graph = interaction_position_graph(woman, man, third)
|
||||
elif "foreplay" in slug:
|
||||
graph = foreplay_position_graph(woman, man)
|
||||
elif "outercourse" in slug:
|
||||
graph = outercourse_position_graph(woman, man)
|
||||
|
||||
Reference in New Issue
Block a user