Files
LittleWhiteBox/modules/wallhaven-background.js
RT15548 593fce3c8c
2025-12-19 02:19:10 +08:00

2183 lines
95 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { extension_settings, getContext } from "../../../../extensions.js";
import { saveSettingsDebounced } from "../../../../../script.js";
import { EXT_ID } from "../core/constants.js";
import { createModuleEvents, event_types } from "../core/event-manager.js";
const MODULE_NAME = "wallhavenBackground";
const messageEvents = createModuleEvents('wallhaven:messages');
const globalEvents = createModuleEvents('wallhaven');
const defaultSettings = {
enabled: false,
bgMode: false,
category: "010",
purity: "100",
opacity: 0.3,
customTags: []
};
const tagWeights = {
custom: 3.0,
characters: 3,
locations: 3,
nsfw_actions: 3,
intimate_settings: 3,
poses: 2,
clothing: 2,
nsfw_body_parts: 2,
activities: 2,
expressions: 1.5,
body_features: 1.5,
nsfw_states: 1.5,
fetish_categories: 1.5,
clothing_states: 1.5,
nsfw_descriptions: 1.5,
colors: 1,
objects: 1,
weather_time: 1,
styles: 1,
emotional_states: 1,
romance_keywords: 1,
body_modifications: 1,
nsfw_sounds: 1
};
const wallhavenTags = {
characters: {
// 基础人称
"女孩": "anime girl", "少女": "anime girl", "女性": "woman", "女人": "woman",
"男孩": "boy", "少年": "boy", "男性": "man", "男人": "man",
"美女": "beautiful woman", "帅哥": "handsome man", "女生": "girl", "男生": "boy",
// 职业角色
"女仆": "maid", "侍女": "maid", "佣人": "maid", "管家": "butler",
"秘书": "secretary", "助理": "assistant", "下属": "subordinate",
"老板": "boss", "上司": "superior", "领导": "leader", "经理": "manager",
"同事": "colleague", "伙伴": "partner", "搭档": "partner",
"客户": "client", "顾客": "customer", "委托人": "client",
// 学校相关
"学生": "student", "学员": "student", "同学": "student",
"男同学": "male student", "女同学": "schoolgirl", "女学生": "schoolgirl", "男学生": "male student",
"老师": "teacher", "教师": "teacher", "先生": "teacher", "导师": "mentor",
"校长": "principal", "教授": "professor", "讲师": "lecturer",
"学姐": "senior student", "学妹": "junior student", "学长": "senior student", "学弟": "junior student",
"班长": "class president", "社长": "club president",
// 医疗相关
"护士": "nurse", "白衣天使": "nurse", "医护": "nurse",
"医生": "doctor", "大夫": "doctor", "医师": "physician",
"病人": "patient", "患者": "patient",
// 家庭关系
"母亲": "mother", "妈妈": "mother", "母": "mother", "妈": "mother",
"父亲": "father", "爸爸": "father", "父": "father", "爸": "father",
"姐姐": "sister", "妹妹": "sister", "哥哥": "brother", "弟弟": "brother",
"女儿": "daughter", "闺女": "daughter", "儿子": "son",
"妻子": "wife", "老婆": "wife", "丈夫": "husband", "老公": "husband",
"岳母": "mother-in-law", "婆婆": "mother-in-law", "丈母娘": "mother-in-law",
"阿姨": "aunt", "叔叔": "uncle", "表姐": "cousin", "表妹": "cousin",
"邻居": "neighbor", "房东": "landlord", "租客": "tenant",
// 特殊身份
"公主": "princess", "殿下": "princess", "王女": "princess",
"王子": "prince", "王子殿下": "prince", "皇子": "prince",
"女王": "queen", "国王": "king", "皇帝": "emperor", "皇后": "empress",
"贵族": "noble", "富家千金": "rich girl", "大小姐": "young lady",
"平民": "commoner", "村民": "villager", "市民": "citizen",
// 二次元角色
"猫娘": "catgirl", "猫女": "catgirl", "猫咪女孩": "catgirl",
"狐娘": "fox girl", "狐狸女孩": "fox girl", "狐仙": "fox girl",
"兔娘": "bunny girl", "兔女郎": "bunny girl", "兔子女孩": "bunny girl",
"狼娘": "wolf girl", "犬娘": "dog girl", "龙娘": "dragon girl",
"魔女": "witch", "女巫": "witch", "巫女": "witch", "魔法少女": "magical girl",
"天使": "angel", "小天使": "angel", "堕天使": "fallen angel",
"恶魔": "demon", "魅魔": "demon", "小恶魔": "demon",
"精灵": "elf", "森林精灵": "elf", "暗精灵": "dark elf",
"吸血鬼": "vampire", "血族": "vampire", "僵尸": "zombie",
"人偶": "doll", "机器人": "android", "人造人": "artificial human",
"外星人": "alien", "异世界人": "otherworld person",
// 职业类型
"忍者": "ninja", "女忍": "ninja", "武士": "warrior", "剑士": "swordsman",
"骑士": "knight", "圣骑士": "paladin", "战士": "warrior",
"法师": "wizard", "魔法师": "wizard", "术士": "sorcerer",
"牧师": "priest", "修女": "nun", "尼姑": "nun",
"盗贼": "thief", "刺客": "assassin", "间谍": "spy",
"雇佣兵": "mercenary", "佣兵": "mercenary", "赏金猎人": "bounty hunter",
// 现代职业
"警察": "police", "警官": "police", "侦探": "detective", "探长": "detective",
"消防员": "firefighter", "消防": "firefighter",
"军人": "soldier", "士兵": "soldier", "特种兵": "special forces",
"飞行员": "pilot", "船长": "captain", "司机": "driver",
"厨师": "chef", "料理师": "chef", "服务员": "waitress",
"调酒师": "bartender", "咖啡师": "barista",
"艺术家": "artist", "画家": "artist", "雕塑家": "sculptor",
"音乐家": "musician", "歌手": "singer", "偶像": "idol",
"演员": "actress", "模特": "model", "舞者": "dancer",
"作家": "writer", "记者": "journalist", "编辑": "editor",
"科学家": "scientist", "研究员": "scientist", "博士": "doctor",
"程序员": "programmer", "工程师": "engineer", "设计师": "designer",
"商人": "businessman", "企业家": "entrepreneur", "投资者": "investor",
// 特殊关系
"新娘": "bride", "新嫁娘": "bride", "新郎": "groom",
"前女友": "ex-girlfriend", "前男友": "ex-boyfriend",
"青梅竹马": "childhood friend", "闺蜜": "best friend", "好友": "friend",
"对手": "rival", "敌人": "enemy", "仇人": "enemy",
"陌生人": "stranger", "路人": "passerby", "访客": "visitor"
},
clothing: {
// 裙装类
"连衣裙": "dress", "裙子": "dress", "长裙": "long dress", "短裙": "short dress",
"迷你裙": "mini dress", "中裙": "midi dress", "蓬蓬裙": "puffy dress",
"紧身裙": "tight dress", "A字裙": "a-line dress", "包臀裙": "pencil skirt",
"百褶裙": "pleated skirt", "伞裙": "circle skirt", "吊带裙": "slip dress",
// 制服类
"校服": "school uniform", "制服": "uniform", "学生服": "school uniform",
"女仆装": "maid outfit", "女仆服": "maid outfit",
"护士服": "nurse outfit", "白大褂": "nurse outfit",
"警服": "police uniform", "军装": "military uniform",
"空姐服": "flight attendant uniform", "服务员服": "waitress uniform",
"OL装": "office lady outfit", "职业装": "business attire",
// 传统服装
"和服": "kimono", "浴衣": "kimono", "振袖": "kimono",
"旗袍": "qipao", "中式服装": "chinese dress", "汉服": "hanfu",
"洛丽塔": "lolita dress", "哥特装": "gothic dress",
// 特殊场合
"婚纱": "wedding dress", "新娘装": "wedding dress", "礼服": "evening gown",
"晚礼服": "evening dress", "舞会裙": "ball gown", "宴会服": "party dress",
"演出服": "performance outfit", "舞台装": "stage outfit",
// 休闲装
"T恤": "t-shirt", "衬衫": "shirt", "衬衣": "blouse",
"吊带": "tank top", "背心": "vest", "卫衣": "hoodie",
"夹克": "jacket", "外套": "coat", "风衣": "trench coat",
"毛衣": "sweater", "针织衫": "knit sweater", "开衫": "cardigan",
// 裤装
"牛仔裤": "jeans", "裤子": "pants", "短裤": "shorts",
"热裤": "hot pants", "紧身裤": "leggings", "喇叭裤": "flare pants",
"西装裤": "suit pants", "休闲裤": "casual pants",
// 运动装
"运动服": "sportswear", "瑜伽服": "yoga outfit", "健身服": "gym wear",
"田径服": "track suit", "篮球服": "basketball uniform",
// 睡衣家居
"睡衣": "pajamas", "居家服": "pajamas", "睡袍": "nightgown",
"浴袍": "bathrobe", "晨袍": "morning robe", "家居服": "loungewear",
// 泳装
"泳装": "swimsuit", "泳衣": "swimsuit", "比基尼": "bikini",
"连体泳衣": "one-piece swimsuit", "三点式": "bikini",
// 内衣
"内衣": "lingerie", "胸罩": "bra", "内裤": "panties",
"文胸": "bra", "胖次": "panties", "三角裤": "briefs",
"平角裤": "boxers", "内衣套装": "lingerie set",
"情趣内衣": "sexy lingerie", "蕾丝内衣": "lace lingerie",
// 袜类
"丝袜": "stockings", "长筒袜": "stockings", "连裤袜": "pantyhose",
"过膝袜": "thigh highs", "短袜": "ankle socks", "船袜": "no-show socks",
"网袜": "fishnet stockings", "白丝": "white stockings", "黑丝": "black stockings",
// 鞋类
"高跟鞋": "high heels", "靴子": "boots", "凉鞋": "sandals",
"平底鞋": "flats", "帆布鞋": "canvas shoes", "运动鞋": "sneakers",
"马丁靴": "combat boots", "长靴": "knee boots", "短靴": "ankle boots",
"拖鞋": "slippers", "人字拖": "flip flops",
// 配饰
"手套": "gloves", "帽子": "hat", "眼镜": "glasses",
"太阳镜": "sunglasses", "发带": "headband", "头巾": "headscarf",
"围巾": "scarf", "披肩": "shawl", "领带": "tie",
"蝴蝶结": "bow tie", "腰带": "belt", "围裙": "apron",
// 首饰
"项链": "necklace", "耳环": "earrings", "戒指": "ring",
"手镯": "bracelet", "脚链": "anklet", "发饰": "hair accessory",
"胸针": "brooch", "手表": "watch"
},
body_features: {
// 发型
"长发": "long hair", "短发": "short hair", "中发": "medium hair",
"马尾": "ponytail", "双马尾": "twintails", "侧马尾": "side ponytail",
"丸子头": "bun", "包子头": "bun", "公主头": "half updo",
"刘海": "bangs", "齐刘海": "straight bangs", "斜刘海": "side bangs",
"卷发": "curly hair", "直发": "straight hair", "波浪发": "wavy hair",
"盘发": "updo", "编发": "braided hair", "麻花辫": "braids",
"单边辫": "side braid", "双辫": "twin braids",
"蓬松发": "voluminous hair", "顺滑发": "silky hair",
// 发色
"黑发": "black hair", "金发": "blonde hair", "棕发": "brown hair",
"白发": "white hair", "银发": "silver hair", "红发": "red hair",
"蓝发": "blue hair", "粉发": "pink hair", "紫发": "purple hair",
"绿发": "green hair", "橙发": "orange hair", "灰发": "gray hair",
"彩虹发": "rainbow hair", "渐变发": "gradient hair",
// 身材
"高个": "tall", "矮个": "short", "娇小": "petite", "高挑": "tall and slender",
"苗条": "slim", "纤细": "slim", "瘦": "thin", "骨感": "skinny",
"丰满": "curvy", "饱满": "voluptuous", "肉感": "plump",
"匀称": "well-proportioned", "性感": "sexy", "优美": "graceful",
// 胸部
"大胸": "large breasts", "巨乳": "huge breasts", "丰满": "large breasts",
"小胸": "small breasts", "贫乳": "small breasts", "平胸": "flat chest",
"挺拔": "perky", "坚挺": "firm", "饱满": "full",
"柔软": "soft", "弹性": "bouncy", "深沟": "cleavage",
// 腿部
"美腿": "beautiful legs", "长腿": "long legs", "细腿": "slender legs",
"修长": "slender", "笔直": "straight", "匀称": "shapely",
"大腿": "thighs", "小腿": "calves", "脚踝": "ankles",
// 皮肤
"白皙": "fair", "雪白": "snow white", "透白": "translucent",
"古铜": "tanned", "小麦色": "wheat colored", "健康": "healthy",
"光滑": "smooth", "细腻": "delicate", "粗糙": "rough",
"红润": "rosy", "苍白": "pale", "有光泽": "glowing",
// 眼睛
"大眼": "big eyes", "小眼": "small eyes", "圆眼": "round eyes",
"细长眼": "narrow eyes", "杏眼": "almond eyes", "桃花眼": "peach blossom eyes",
"双眼皮": "double eyelids", "单眼皮": "single eyelids",
"长睫毛": "long eyelashes", "浓睫毛": "thick eyelashes",
// 特殊特征
"猫耳": "cat ears", "狐耳": "fox ears", "兔耳": "bunny ears",
"狼耳": "wolf ears", "犬耳": "dog ears", "精灵耳": "elf ears",
"翅膀": "wings", "天使翅膀": "angel wings", "恶魔翅膀": "demon wings",
"尾巴": "tail", "猫尾": "cat tail", "狐尾": "fox tail",
"角": "horns", "恶魔角": "demon horns", "独角": "unicorn horn",
// 体格
"肌肉": "muscular", "强壮": "muscular", "健美": "athletic",
"结实": "sturdy", "精瘦": "lean", "厚实": "solid",
"柔弱": "delicate", "纤弱": "fragile", "娇弱": "frail",
// 面部特征
"圆脸": "round face", "瓜子脸": "oval face", "方脸": "square face",
"鹅蛋脸": "oval face", "心形脸": "heart-shaped face",
"高鼻梁": "high nose bridge", "小鼻子": "small nose",
"厚嘴唇": "thick lips", "薄嘴唇": "thin lips", "樱桃嘴": "cherry lips",
"尖下巴": "pointed chin", "圆下巴": "round chin",
"酒窝": "dimples", "笑容": "smile", "梨涡": "dimples",
// 其他
"胡子": "beard", "胡须": "mustache", "络腮胡": "full beard",
"光头": "bald", "秃头": "bald", "寸头": "buzz cut",
"疤痕": "scar", "纹身": "tattoo", "胎记": "birthmark",
"雀斑": "freckles", "痣": "mole", "美人痣": "beauty mark",
"虎牙": "fangs", "小虎牙": "small fangs"
},
expressions: {
// 快乐情绪
"微笑": "smile", "笑": "smile", "开心": "happy", "高兴": "happy",
"大笑": "laughing", "窃笑": "giggling", "傻笑": "silly smile",
"甜笑": "sweet smile", "温和笑": "gentle smile", "灿烂笑": "bright smile",
"兴奋": "excited", "激动": "excited", "愉快": "cheerful",
"欣喜": "delighted", "狂喜": "ecstatic", "满意": "satisfied",
// 悲伤情绪
"伤心": "sad", "难过": "sad", "哭": "crying", "流泪": "tears",
"大哭": "sobbing", "抽泣": "sniffling", "眼泪汪汪": "teary eyes",
"悲伤": "sorrowful", "沮丧": "depressed", "失落": "disappointed",
"绝望": "despair", "痛苦": "painful", "心碎": "heartbroken",
// 愤怒情绪
"生气": "angry", "愤怒": "angry", "恼火": "angry",
"暴怒": "furious", "发火": "mad", "气愤": "indignant",
"不满": "dissatisfied", "抱怨": "complaining", "怨恨": "resentful",
// 害羞情绪
"害羞": "shy", "脸红": "blushing", "羞涩": "shy",
"害臊": "bashful", "腼腆": "timid", "不好意思": "embarrassed",
"羞耻": "ashamed", "窘迫": "flustered", "局促": "awkward",
// 惊讶情绪
"惊讶": "surprised", "吃惊": "surprised", "震惊": "shocked",
"惊愕": "astonished", "惊恐": "horrified", "目瞪口呆": "stunned",
"困惑": "confused", "疑惑": "puzzled", "迷茫": "bewildered",
// 温柔情绪
"温柔": "gentle", "柔和": "gentle", "亲切": "gentle",
"慈祥": "kind", "和善": "friendly", "温暖": "warm",
"关爱": "caring", "怜爱": "tender", "宠溺": "doting",
// 严肃情绪
"严肃": "serious", "认真": "serious", "冷静": "calm",
"严厉": "stern", "冷漠": "indifferent", "无表情": "expressionless",
"冷酷": "cold", "淡漠": "aloof", "疏远": "distant",
// 疲倦情绪
"困": "sleepy", "累": "tired", "疲倦": "tired",
"疲惫": "exhausted", "困倦": "drowsy", "无精打采": "listless",
"虚弱": "weak", "萎靡": "dispirited", "懒散": "lazy",
// 其他情绪
"紧张": "nervous", "担心": "worried", "焦虑": "anxious",
"恐惧": "fearful", "害怕": "scared", "胆怯": "timid",
"自信": "confident", "骄傲": "proud", "得意": "smug",
"傲慢": "arrogant", "轻蔑": "contemptuous", "不屑": "disdainful",
"好奇": "curious", "感兴趣": "interested", "专注": "focused",
"集中": "concentrated", "沉思": "contemplating", "思考": "thinking",
"无聊": "bored", "厌倦": "tired of", "烦躁": "irritated",
"期待": "expectant", "渴望": "longing", "向往": "yearning"
},
poses: {
// 基础姿势
"站着": "standing", "站立": "standing", "直立": "upright",
"坐着": "sitting", "坐下": "sitting", "端坐": "sitting properly",
"躺着": "lying", "躺下": "lying", "平躺": "lying flat",
"跪着": "kneeling", "下跪": "kneeling", "跪坐": "seiza",
"蹲着": "squatting", "蹲下": "crouching", "半蹲": "half squat",
// 动作姿势
"走路": "walking", "行走": "walking", "漫步": "strolling",
"跑步": "running", "奔跑": "running", "疾跑": "sprinting",
"跳跃": "jumping", "蹦跳": "hopping", "飞跃": "leaping",
"跳舞": "dancing", "舞蹈": "dancing", "旋转": "spinning",
"伸展": "stretching", "弯腰": "bending", "下腰": "backbend",
// 手部动作
"举手": "arms up", "抬手": "arms up", "双手举起": "both arms up",
"伸手": "reaching out", "指向": "pointing", "挥手": "waving",
"鼓掌": "clapping", "握拳": "clenched fist", "比心": "heart gesture",
"捂脸": "covering face", "托腮": "chin rest", "撑头": "head rest",
// 互动姿势
"拥抱": "hugging", "抱着": "hugging", "搂抱": "embracing",
"牵手": "holding hands", "握手": "handshake", "搀扶": "supporting",
"背着": "carrying on back", "抱起": "lifting up", "搂腰": "arm around waist",
// 生活姿势
"睡觉": "sleeping", "熟睡": "sleeping", "打盹": "napping",
"看书": "reading", "阅读": "reading", "翻书": "turning pages",
"写字": "writing", "书写": "writing", "画画": "drawing",
"工作": "working", "学习": "studying", "思考": "thinking",
"做作业": "homework", "写作业": "homework", "考试": "taking exam",
// 运动姿势
"游泳": "swimming", "潜水": "diving", "跳水": "diving",
"爬山": "climbing", "攀登": "climbing", "攀岩": "rock climbing",
"骑车": "cycling", "开车": "driving", "骑马": "horseback riding",
"滑雪": "skiing", "滑冰": "ice skating", "溜冰": "skating",
"健身": "exercising", "瑜伽": "yoga", "拉伸": "stretching",
// 战斗姿势
"战斗": "fighting", "格斗": "combat", "对战": "battle",
"攻击": "attacking", "防御": "defending", "出拳": "punching",
"踢腿": "kicking", "挥剑": "sword swinging", "射箭": "archery",
// 表演姿势
"唱歌": "singing", "演奏": "playing instrument", "表演": "performing",
"朗诵": "reciting", "演讲": "giving speech", "主持": "hosting",
// 特殊姿势
"冥想": "meditation", "祈祷": "praying", "许愿": "making wish",
"仰望": "looking up", "俯视": "looking down", "回首": "looking back",
"侧身": "side view", "背影": "back view", "正面": "front view",
"倚靠": "leaning", "靠墙": "leaning against wall", "趴着": "lying on stomach"
},
locations: {
// 居住场所
"卧室": "bedroom", "房间": "bedroom", "寝室": "bedroom",
"客厅": "living room", "起居室": "living room", "大厅": "hall",
"厨房": "kitchen", "灶间": "kitchen", "餐厅": "dining room",
"浴室": "bathroom", "洗手间": "bathroom", "厕所": "toilet",
"阳台": "balcony", "露台": "terrace", "庭院": "courtyard",
"花园": "garden", "后院": "backyard", "前院": "front yard",
"地下室": "basement", "阁楼": "attic", "储藏室": "storage room",
// 学校场所
"教室": "classroom", "课堂": "classroom", "学校": "school",
"图书馆": "library", "书馆": "library", "阅览室": "reading room",
"实验室": "laboratory", "研究室": "laboratory", "计算机房": "computer room",
"体育馆": "gymnasium", "操场": "playground", "运动场": "sports field",
"食堂": "cafeteria", "宿舍": "dormitory", "社团室": "club room",
"校园": "campus", "校门": "school gate", "走廊": "corridor",
// 工作场所
"办公室": "office", "工作室": "office", "会议室": "meeting room",
"公司": "company", "企业": "corporation", "工厂": "factory",
"车间": "workshop", "仓库": "warehouse", "商店": "shop",
"超市": "supermarket", "商场": "shopping mall", "市场": "market",
"银行": "bank", "邮局": "post office", "政府": "government office",
// 医疗场所
"医院": "hospital", "诊所": "hospital", "急诊室": "emergency room",
"病房": "hospital room", "手术室": "operating room", "药房": "pharmacy",
// 娱乐场所
"咖啡厅": "cafe", "咖啡店": "cafe", "茶馆": "tea house",
"餐厅": "restaurant", "饭店": "restaurant", "快餐店": "fast food",
"酒吧": "bar", "夜店": "nightclub", "KTV": "karaoke",
"电影院": "cinema", "剧院": "theater", "音乐厅": "concert hall",
"游乐园": "amusement park", "动物园": "zoo", "水族馆": "aquarium",
"博物馆": "museum", "美术馆": "art gallery", "展览馆": "exhibition hall",
// 自然场所
"公园": "park", "广场": "square", "街道": "street",
"海边": "beach", "沙滩": "beach", "海滩": "beach",
"森林": "forest", "树林": "forest", "丛林": "jungle",
"山": "mountain", "高山": "mountain", "山顶": "mountain peak",
"湖边": "lake", "湖泊": "lake", "河边": "riverside",
"河流": "river", "溪流": "stream", "瀑布": "waterfall",
"草原": "grassland", "田野": "field", "农场": "farm",
"沙漠": "desert", "雪山": "snowy mountain", "冰川": "glacier",
// 交通场所
"火车站": "train station", "地铁站": "subway station", "公交站": "bus stop",
"机场": "airport", "港口": "port", "码头": "dock",
"停车场": "parking lot", "加油站": "gas station",
// 宗教场所
"教堂": "church", "寺庙": "temple", "清真寺": "mosque",
"神社": "shrine", "修道院": "monastery",
// 特殊场所
"城堡": "castle", "宫殿": "castle", "塔楼": "tower",
"桥": "bridge", "大桥": "bridge", "隧道": "tunnel",
"屋顶": "rooftop", "天台": "rooftop", "楼顶": "rooftop",
"地铁": "subway", "电梯": "elevator", "楼梯": "stairs",
"监狱": "prison", "法院": "courthouse", "警察局": "police station",
"温泉": "hot spring", "海岛": "island", "洞穴": "cave",
"废墟": "ruins", "遗迹": "ruins", "秘境": "secret place"
},
weather_time: {
// 天气
"晴天": "sunny", "阳光": "sunny", "晴朗": "sunny",
"多云": "cloudy", "阴天": "cloudy", "乌云": "dark clouds",
"下雨": "rain", "雨天": "rainy", "雨": "rain",
"毛毛雨": "drizzle", "大雨": "heavy rain", "暴雨": "storm",
"雷雨": "thunderstorm", "闪电": "lightning", "打雷": "thunder",
"下雪": "snow", "雪天": "snowy", "雪": "snow",
"暴雪": "blizzard", "雪花": "snowflakes", "雪景": "snowy scene",
"雾": "fog", "薄雾": "mist", "浓雾": "thick fog",
"风": "wind", "微风": "breeze", "强风": "strong wind",
"台风": "typhoon", "龙卷风": "tornado", "沙尘暴": "sandstorm",
// 时间
"日出": "sunrise", "清晨": "morning", "早晨": "morning",
"上午": "morning", "中午": "noon", "下午": "afternoon",
"日落": "sunset", "黄昏": "sunset", "夕阳": "sunset",
"傍晚": "evening", "夜晚": "night", "晚上": "night",
"深夜": "night", "午夜": "midnight", "凌晨": "dawn",
"白天": "day", "日间": "day", "夜间": "night",
// 季节
"春天": "spring", "春季": "spring", "初春": "early spring",
"夏天": "summer", "夏季": "summer", "盛夏": "midsummer",
"秋天": "autumn", "秋季": "autumn", "深秋": "late autumn",
"冬天": "winter", "冬季": "winter", "隆冬": "midwinter",
// 天象
"月光": "moonlight", "满月": "full moon", "新月": "new moon",
"星空": "starry sky", "繁星": "stars", "银河": "milky way",
"彩虹": "rainbow", "双彩虹": "double rainbow", "流星": "meteor",
"日食": "solar eclipse", "月食": "lunar eclipse", "极光": "aurora",
// 气候
"炎热": "hot", "温暖": "warm", "凉爽": "cool",
"寒冷": "cold", "冰冷": "freezing", "严寒": "bitter cold",
"潮湿": "humid", "干燥": "dry", "闷热": "muggy"
},
colors: {
// 基础颜色
"红色": "red", "红": "red", "朱红": "red", "深红": "dark red",
"粉色": "pink", "粉红": "pink", "粉": "pink", "浅粉": "light pink",
"橙色": "orange", "橘色": "orange", "橙": "orange", "橘红": "red orange",
"黄色": "yellow", "黄": "yellow", "金黄": "golden yellow", "柠檬黄": "lemon yellow",
"绿色": "green", "绿": "green", "翠绿": "emerald green", "深绿": "dark green",
"蓝色": "blue", "蓝": "blue", "天蓝": "sky blue", "深蓝": "dark blue",
"紫色": "purple", "紫": "purple", "紫罗兰": "violet", "深紫": "dark purple",
"黑色": "black", "黑": "black", "乌黑": "jet black", "深黑": "deep black",
"白色": "white", "白": "white", "洁白": "pure white", "雪白": "snow white",
"灰色": "gray", "灰": "gray", "银灰": "silver gray", "深灰": "dark gray",
"棕色": "brown", "褐色": "brown", "咖啡色": "coffee brown", "巧克力色": "chocolate",
// 金属色
"银色": "silver", "金色": "gold", "铜色": "copper", "青铜": "bronze",
"铂金": "platinum", "玫瑰金": "rose gold",
// 特殊色彩
"彩虹色": "rainbow", "渐变色": "gradient", "透明": "transparent",
"荧光": "fluorescent", "金属": "metallic", "珠光": "pearl",
"哑光": "matte", "亮光": "glossy", "闪光": "glitter"
},
objects: {
// 书籍文具
"书": "book", "书本": "book", "图书": "book", "小说": "novel",
"教科书": "textbook", "字典": "dictionary", "杂志": "magazine",
"笔": "pen", "钢笔": "fountain pen", "铅笔": "pencil", "毛笔": "brush pen",
"纸": "paper", "笔记本": "notebook", "日记": "diary", "便签": "sticky note",
// 花卉植物
"花": "flower", "鲜花": "flower", "花朵": "flower", "花束": "bouquet",
"玫瑰": "rose", "樱花": "cherry blossom", "向日葵": "sunflower",
"郁金香": "tulip", "百合": "lily", "菊花": "chrysanthemum",
"树": "tree", "盆栽": "potted plant", "仙人掌": "cactus",
// 餐具茶具
"杯子": "cup", "茶杯": "teacup", "咖啡杯": "coffee cup",
"水杯": "water glass", "酒杯": "wine glass", "马克杯": "mug",
"盘子": "plate", "碗": "bowl", "勺子": "spoon", "叉子": "fork",
"筷子": "chopsticks", "刀": "knife", "茶壶": "teapot",
// 装饰品
"镜子": "mirror", "时钟": "clock", "钟": "clock", "闹钟": "alarm clock",
"相框": "photo frame", "画": "painting", "海报": "poster",
"蜡烛": "candle", "台灯": "desk lamp", "花瓶": "vase",
// 武器道具
"剑": "sword", "刀": "sword", "匕首": "dagger", "长矛": "spear",
"弓": "bow", "箭": "arrow", "盾": "shield", "铠甲": "armor",
"魔法棒": "magic wand", "法杖": "staff", "水晶球": "crystal ball",
// 乐器
"吉他": "guitar", "钢琴": "piano", "小提琴": "violin",
"笛子": "flute", "鼓": "drum", "萨克斯": "saxophone",
// 电子设备
"电脑": "computer", "笔记本": "laptop", "平板": "tablet",
"手机": "phone", "相机": "camera", "照相机": "camera",
"电视": "television", "收音机": "radio", "耳机": "headphones",
// 日用品
"伞": "umbrella", "雨伞": "umbrella", "遮阳伞": "parasol",
"包": "bag", "书包": "bag", "手提包": "handbag", "背包": "backpack",
"钱包": "wallet", "钥匙": "key", "锁": "lock",
"枕头": "pillow", "抱枕": "pillow", "毯子": "blanket",
"被子": "quilt", "床单": "bedsheet", "毛巾": "towel",
// 交通工具
"汽车": "car", "自行车": "bicycle", "摩托车": "motorcycle",
"公交车": "bus", "出租车": "taxi", "卡车": "truck",
"飞机": "airplane", "直升机": "helicopter", "船": "ship",
"游艇": "yacht", "火车": "train", "地铁": "subway",
// 食物饮品
"咖啡": "coffee", "茶": "tea", "水": "water", "果汁": "juice",
"蛋糕": "cake", "面包": "bread", "饼干": "cookie",
"苹果": "apple", "香蕉": "banana", "橙子": "orange",
"巧克力": "chocolate", "糖果": "candy", "冰淇淋": "ice cream",
// 首饰配件
"项链": "necklace", "手链": "bracelet", "戒指": "ring",
"耳环": "earrings", "胸针": "brooch", "手表": "watch",
"皇冠": "crown", "头饰": "hair accessory", "发卡": "hair clip",
// 运动用品
"球": "ball", "篮球": "basketball", "足球": "soccer ball",
"网球": "tennis ball", "乒乓球": "ping pong ball",
"球拍": "racket", "滑板": "skateboard", "轮滑鞋": "roller skates",
// 玩具
"玩偶": "doll", "泰迪熊": "teddy bear", "毛绒玩具": "stuffed animal",
"积木": "building blocks", "拼图": "puzzle", "棋": "chess",
"扑克": "playing cards", "骰子": "dice", "风筝": "kite"
},
styles: {
// 美感风格
"可爱": "cute", "美丽": "beautiful", "漂亮": "pretty",
"美": "beautiful", "绝美": "stunning", "惊艳": "gorgeous",
"优雅": "elegant", "高贵": "noble", "华丽": "gorgeous",
"精致": "delicate", "完美": "perfect", "迷人": "charming",
// 性感风格
"性感": "sexy", "诱惑": "seductive", "魅惑": "seductive",
"撩人": "alluring", "火辣": "hot", "妖娆": "enchanting",
"风情": "charming", "妩媚": "seductive", "勾人": "alluring",
// 纯真风格
"清纯": "innocent", "纯洁": "pure", "天真": "innocent",
"单纯": "naive", "纯真": "pure", "清新": "fresh",
"自然": "natural", "朴素": "simple", "清雅": "elegant",
// 成熟风格
"成熟": "mature", "稳重": "mature", "知性": "intellectual",
"干练": "capable", "职业": "professional", "严谨": "rigorous",
"端庄": "dignified", "庄重": "solemn", "典雅": "elegant",
// 活力风格
"活泼": "lively", "开朗": "cheerful", "阳光": "bright",
"青春": "youthful", "朝气": "energetic", "活力": "vibrant",
"热情": "passionate", "积极": "positive", "乐观": "optimistic",
// 冷酷风格
"神秘": "mysterious", "冷酷": "cool", "高冷": "cold",
"冰冷": "icy", "冷漠": "indifferent", "疏离": "distant",
"孤独": "lonely", "忧郁": "melancholy", "深沉": "deep",
// 温暖风格
"温暖": "warm", "舒适": "comfortable", "宁静": "peaceful",
"温和": "gentle", "慈祥": "kind", "亲切": "friendly",
"贴心": "caring", "体贴": "considerate", "善良": "kind",
// 浪漫风格
"浪漫": "romantic", "梦幻": "dreamy", "唯美": "aesthetic",
"诗意": "poetic", "文艺": "artistic", "小清新": "fresh",
"治愈": "healing", "暖心": "heartwarming", "甜美": "sweet",
// 奇幻风格
"奇幻": "fantasy", "魔幻": "magical", "神秘": "mysterious",
"超现实": "surreal", "梦境": "dreamlike", "虚幻": "illusory",
// 时代风格
"古典": "classic", "复古": "vintage", "古风": "ancient style",
"现代": "modern", "时尚": "fashionable", "前卫": "avant-garde",
"未来": "futuristic", "科幻": "sci-fi", "赛博朋克": "cyberpunk",
// 男性魅力
"帅气": "handsome", "英俊": "handsome", "潇洒": "dashing",
"俊美": "handsome", "阳刚": "masculine", "威严": "dignified",
"强大": "powerful", "威猛": "mighty", "勇敢": "brave",
"绅士": "gentleman", "风度": "graceful", "魅力": "charismatic",
"霸气": "domineering", "王者": "kingly", "领袖": "leadership"
},
activities: {
// 学习活动
"学习": "studying", "上课": "attending class", "考试": "exam",
"复习": "reviewing", "预习": "previewing", "做题": "solving problems",
"做作业": "homework", "写作业": "homework", "背书": "memorizing",
"研究": "research", "实验": "experiment", "讨论": "discussion",
// 生活活动
"做饭": "cooking", "吃饭": "eating", "用餐": "dining",
"喝茶": "drinking tea", "喝咖啡": "drinking coffee", "品茶": "tea tasting",
"洗澡": "bathing", "沐浴": "bathing", "泡澡": "bathing",
"洗漱": "washing up", "刷牙": "brushing teeth", "洗脸": "washing face",
"睡觉": "sleeping", "午睡": "napping", "休息": "resting",
"起床": "getting up", "醒来": "waking up",
// 购物娱乐
"购物": "shopping", "逛街": "shopping", "买东西": "shopping",
"逛商场": "mall shopping", "网购": "online shopping",
"看电影": "watching movie", "看电视": "watching TV", "追剧": "binge watching",
"听音乐": "listening to music", "唱歌": "singing", "唱K": "karaoke",
"游戏": "gaming", "玩耍": "playing", "娱乐": "entertainment",
"聊天": "chatting", "谈话": "talking", "交流": "communicating",
// 运动健身
"运动": "sports", "健身": "fitness", "锻炼": "exercise",
"跑步": "running", "慢跑": "jogging", "散步": "walking",
"游泳": "swimming", "潜水": "diving", "跳水": "diving",
"登山": "mountain climbing", "徒步": "hiking", "骑行": "cycling",
"瑜伽": "yoga", "舞蹈": "dancing", "跳舞": "dancing",
"太极": "tai chi", "武术": "martial arts", "拳击": "boxing",
// 工作活动
"工作": "working", "加班": "overtime", "会议": "meeting",
"开会": "attending meeting", "谈判": "negotiation", "签约": "signing contract",
"出差": "business trip", "培训": "training", "实习": "internship",
// 社交活动
"聚会": "party", "庆祝": "celebration", "生日": "birthday",
"聚餐": "group dining", "野餐": "picnic", "烧烤": "barbecue",
"约会": "dating", "恋爱": "romance", "表白": "confession",
"求婚": "proposal", "结婚": "wedding", "婚礼": "wedding ceremony",
"蜜月": "honeymoon", "旅行": "travel", "度假": "vacation",
"观光": "sightseeing", "旅游": "tourism", "探险": "adventure",
// 文艺活动
"看书": "reading", "阅读": "reading", "写作": "writing",
"画画": "drawing", "绘画": "painting", "摄影": "photography",
"书法": "calligraphy", "雕刻": "carving", "手工": "handicraft",
"编织": "knitting", "刺绣": "embroidery", "陶艺": "pottery",
// 情感互动
"调戏": "teasing", "戏弄": "teasing", "挑逗": "flirting",
"撩": "flirting", "撩拨": "flirting", "勾引": "seduction",
"诱惑": "seduction", "魅惑": "seduction", "撒娇": "acting cute",
"卖萌": "acting cute", "害羞": "shy", "脸红": "blushing",
"接吻": "kissing", "亲吻": "kissing", "亲": "kissing",
"拥抱": "hugging", "抱": "hugging", "搂": "embracing",
"牵手": "holding hands", "握手": "handshake",
"抚摸": "caressing", "爱抚": "caressing", "按摩": "massage",
"安慰": "comforting", "关心": "caring", "照顾": "taking care",
// 窥视相关
"偷看": "peeking", "窥视": "voyeur", "偷窥": "voyeur",
"暗中观察": "secretly observing", "跟踪": "following",
"展示": "showing", "炫耀": "showing off", "露出": "exposing",
"表现": "performing", "演示": "demonstrating",
// 梦境活动
"梦": "dreaming", "做梦": "dreaming", "梦见": "dreaming",
"梦游": "sleepwalking", "噩梦": "nightmare", "美梦": "sweet dream",
// 思考活动
"思考": "thinking", "考虑": "considering", "琢磨": "pondering",
"沉思": "contemplating", "反思": "reflecting", "冥想": "meditation",
"发呆": "daydreaming", "走神": "spacing out", "幻想": "fantasizing",
// 创作活动
"创作": "creating", "发明": "inventing", "设计": "designing",
"制作": "making", "建造": "building", "构建": "constructing",
"修理": "repairing", "维修": "fixing", "改造": "renovating"
},
body_parts: {
// 头部
"头": "head", "头部": "head", "脑袋": "head",
"脸": "face", "面部": "face", "容颜": "face",
"额头": "forehead", "脸颊": "cheeks", "下巴": "chin",
"眼睛": "eyes", "眼": "eyes", "眼神": "gaze", "目光": "gaze",
"眉毛": "eyebrows", "睫毛": "eyelashes", "眼皮": "eyelids",
"鼻子": "nose", "鼻": "nose", "鼻梁": "nose bridge",
"嘴": "mouth", "嘴唇": "lips", "舌头": "tongue",
"牙齿": "teeth", "虎牙": "fangs", "门牙": "front teeth",
"耳朵": "ears", "耳": "ears", "耳垂": "earlobes",
"头发": "hair", "发型": "hairstyle", "刘海": "bangs",
// 颈部胸部
"脖子": "neck", "颈": "neck", "咽喉": "throat",
"肩膀": "shoulders", "肩": "shoulders", "锁骨": "collarbone",
"胸": "breasts", "胸部": "breasts", "乳房": "breasts",
"胸膛": "chest", "胸口": "chest", "心脏": "heart",
// 手臂手部
"手臂": "arms", "臂": "arms", "上臂": "upper arms",
"前臂": "forearms", "肘": "elbows", "肘部": "elbows",
"手": "hands", "手掌": "palms", "手背": "back of hands",
"手指": "fingers", "拇指": "thumbs", "食指": "index fingers",
"中指": "middle fingers", "无名指": "ring fingers", "小指": "pinky fingers",
"指甲": "nails", "手腕": "wrists", "腕": "wrists",
// 躯干
"身体": "body", "身材": "figure", "体型": "body type",
"背": "back", "后背": "back", "脊背": "spine",
"腰": "waist", "腰部": "waist", "细腰": "slim waist",
"肚子": "belly", "腹部": "abdomen", "腹": "abdomen",
"肚脐": "navel", "小腹": "lower abdomen",
"臀部": "hips", "屁股": "butt", "臀": "buttocks",
// 腿部足部
"腿": "legs", "大腿": "thighs", "小腿": "calves",
"膝盖": "knees", "膝": "knees", "脚踝": "ankles",
"脚": "feet", "足": "feet", "脚掌": "soles",
"脚趾": "toes", "脚指": "toes", "脚跟": "heels",
// 皮肤相关
"皮肤": "skin", "肌肤": "skin", "体肤": "skin",
"毛孔": "pores", "汗": "sweat", "体温": "body temperature",
// 内衣相关
"胸罩": "bra", "文胸": "bra", "内衣": "underwear",
"内裤": "panties", "底裤": "underwear", "三角裤": "briefs",
"胖次": "panties", "安全裤": "safety shorts"
},
nsfw_actions: {
// 基础行为
"做爱": "sex", "性爱": "sex", "交配": "mating", "性交": "intercourse",
"爱爱": "making love", "啪啪": "sex", "嘿咻": "sex",
// 插入动作
"插入": "penetration", "进入": "penetration", "插": "insertion",
"深入": "deep penetration", "浅入": "shallow penetration",
"刺入": "thrusting in", "顶入": "pushing in",
// 律动动作
"抽插": "thrusting", "律动": "thrusting", "顶": "thrusting",
"冲撞": "pounding", "撞击": "hitting", "摩擦": "rubbing",
"研磨": "grinding", "扭动": "twisting", "起伏": "undulating",
// 高潮相关
"高潮": "orgasm", "达到高潮": "climax", "巅峰": "peak",
"射精": "ejaculation", "释放": "release", "爆发": "explosion",
"喷": "squirting", "涌出": "gushing", "流出": "flowing",
// 口部动作
"口交": "oral sex", "含": "sucking", "舔": "licking",
"吸": "sucking", "吮": "sucking", "咬": "biting",
"亲": "kissing", "深吻": "deep kiss", "法式接吻": "french kiss",
// 体位相关
"肛交": "anal sex", "后入": "doggy style", "骑乘": "cowgirl",
"传教士": "missionary", "侧位": "side position", "反向": "reverse",
"站立": "standing position", "坐位": "sitting position",
// 自慰相关
"手淫": "masturbation", "自慰": "masturbation", "撸": "stroking",
"套弄": "stroking", "摩擦": "rubbing", "刺激": "stimulation",
// 抚摸动作
"指交": "fingering", "抚弄": "fondling", "揉": "massaging",
"搓": "rubbing", "捏": "pinching", "压": "pressing",
"按": "pressing", "推": "pushing", "拉": "pulling",
// 体液相关
"爱液": "love juice", "精液": "semen", "体液": "bodily fluids",
"分泌": "secretion", "润滑": "lubrication", "湿润": "moisture",
// 状态描述
"湿润": "wet", "润滑": "lubricated", "干燥": "dry",
"紧": "tight", "松": "loose", "深": "deep", "浅": "shallow",
"热": "hot", "温暖": "warm", "冰凉": "cold",
"快": "fast", "慢": "slow", "用力": "hard", "轻": "gentle",
"粗暴": "rough", "温柔": "gentle", "激烈": "intense", "缓慢": "slow"
},
nsfw_body_parts: {
// 男性器官
"阴茎": "penis", "鸡巴": "cock", "肉棒": "dick", "老二": "dick",
"鸡鸡": "penis", "小弟弟": "penis", "那话儿": "penis",
"龟头": "glans", "包皮": "foreskin", "马眼": "urethral opening",
"睾丸": "testicles", "蛋蛋": "balls", "精囊": "seminal vesicles",
// 女性器官
"阴道": "vagina", "小穴": "pussy", "阴唇": "labia", "花瓣": "labia",
"阴蒂": "clitoris", "豆豆": "clitoris", "小核": "clitoris",
"阴户": "vulva", "私处": "private parts", "花径": "vagina",
"子宫": "womb", "宫口": "cervix", "G点": "g-spot", "敏感点": "sensitive spot",
// 共同部位
"肛门": "anus", "菊花": "asshole", "后庭": "backdoor", "屁眼": "butthole",
"会阴": "perineum", "下体": "genitals", "性器": "sex organ",
"私密处": "intimate parts", "敏感带": "erogenous zone",
// 胸部
"乳头": "nipples", "奶头": "nipples", "乳晕": "areola",
"奶子": "tits", "胸脯": "breasts", "酥胸": "soft breasts",
"双峰": "twin peaks", "玉兔": "breasts", "雪峰": "white breasts",
// 其他敏感部位
"大腿根": "inner thighs", "腿间": "between legs", "股间": "crotch",
"后穴": "back hole", "前穴": "front hole", "蜜穴": "honey pot",
"花心": "deep inside", "花芯": "core", "深处": "deep inside",
// 生理反应
"勃起": "erection", "坚挺": "stiff", "充血": "engorged",
"湿润": "wet", "分泌": "secreting", "流水": "dripping",
"收缩": "contracting", "痉挛": "spasming", "颤抖": "trembling",
// 特殊词汇
"前列腺": "prostate", "尿道": "urethra", "处女膜": "hymen",
"欲火": "lust", "春情": "arousal", "情欲": "passion"
},
nsfw_states: {
// 男性状态
"勃起": "erect", "硬": "hard", "坚挺": "stiff", "挺立": "standing",
"半勃": "semi-erect", "软": "soft", "疲软": "limp",
"胀大": "swollen", "充血": "engorged", "青筋暴起": "veiny",
// 女性状态
"湿": "wet", "潮湿": "moist", "流水": "dripping", "湿润": "lubricated",
"干涩": "dry", "紧致": "tight", "松弛": "loose",
"夹紧": "clenching", "收缩": "contracting", "痉挛": "spasming",
// 共同状态
"胀": "swollen", "肿": "enlarged", "充血": "engorged",
"敏感": "sensitive", "酥麻": "tingling", "颤抖": "trembling",
"战栗": "shivering", "痉挛": "convulsing", "抽搐": "twitching",
// 情绪状态
"兴奋": "aroused", "激动": "excited", "冲动": "horny",
"发情": "in heat", "春心荡漾": "aroused", "欲火焚身": "lustful",
"欲火": "lustful", "渴望": "craving", "饥渴": "thirsty",
"急需": "desperate", "忍耐": "enduring", "煎熬": "suffering",
// 满足状态
"满足": "satisfied", "充实": "fulfilled", "空虚": "empty",
"饱满": "full", "撑胀": "stretched", "填满": "filled",
"深入": "deep", "顶到": "hitting", "碰到": "touching",
// 感觉状态
"疼": "painful", "痛": "aching", "酸": "sore",
"爽": "pleasurable", "舒服": "comfortable", "快感": "pleasure",
"酥": "tingling", "麻": "numb", "痒": "itchy",
"热": "hot", "烫": "burning", "凉": "cool",
"涨": "swelling", "胀": "bloated", "紧": "tight",
// 程度状态
"轻微": "slight", "强烈": "intense", "剧烈": "violent",
"温和": "gentle", "激烈": "fierce", "疯狂": "crazy",
"缓慢": "slow", "急促": "rapid", "持续": "continuous"
},
nsfw_sounds: {
// 呻吟声
"呻吟": "moaning", "叫床": "moaning", "娇喘": "panting",
"喘息": "breathing heavily", "急喘": "panting", "粗喘": "heavy breathing",
// 基础音节
"哼": "humming", "嗯": "mmm", "唔": "mmm",
"啊": "ah", "哦": "oh", "噢": "oh",
"嘤": "whimpering", "嘤嘤": "whimpering", "嘤嘤嘤": "whimpering",
// 高音调
"尖叫": "screaming", "尖声": "high-pitched", "细声": "thin voice",
"呼喊": "crying out", "大叫": "shouting", "惊叫": "exclaiming",
// 低音调
"低吟": "groaning", "闷哼": "muffled moan", "低喃": "mumbling",
"嘟囔": "muttering", "咕哝": "grumbling", "轻哼": "soft humming",
// 情绪音
"啜泣": "sobbing", "哽咽": "choking", "抽泣": "sniffling",
"颤音": "trembling voice", "破音": "voice breaking",
// 生理音
"喘气": "gasping", "倒抽气": "sharp intake", "屏息": "holding breath",
"换气": "catching breath", "深呼吸": "deep breathing",
// 其他音效
"叫声": "vocal", "声音": "sounds", "噪音": "noise",
"音调": "tone", "音量": "volume", "回音": "echo",
"轻声": "whisper", "细语": "soft voice", "耳语": "whispering",
"颤抖": "trembling", "战栗": "shivering", "哆嗦": "quivering"
},
nsfw_descriptions: {
// 基础描述
"色情": "pornographic", "淫荡": "lewd", "下流": "vulgar",
"猥亵": "obscene", "淫秽": "indecent", "不雅": "improper",
"淫乱": "promiscuous", "放荡": "wanton", "骚": "slutty",
"浪": "naughty", "风骚": "seductive", "妖艳": "bewitching",
// 性格特征
"骚货": "slut", "淫娃": "sex kitten", "小妖精": "little minx",
"小浪蹄子": "little slut", "狐狸精": "vixen", "妖女": "seductress",
"处女": "virgin", "纯洁": "pure", "清纯": "innocent",
"无辜": "innocent", "天真": "naive", "单纯": "simple",
// 经验程度
"经验": "experienced", "老练": "skilled", "熟练": "proficient",
"熟女": "mature woman", "老司机": "experienced", "新手": "beginner",
"生涩": "inexperienced", "青涩": "green", "稚嫩": "tender",
// 特殊嗜好
"禁忌": "taboo", "变态": "pervert", "扭曲": "twisted",
"病态": "sick", "不正常": "abnormal", "特殊": "special",
"癖好": "fetish", "嗜好": "preference", "口味": "taste",
// 权力关系
"调教": "training", "驯服": "taming", "征服": "conquering",
"支配": "domination", "统治": "ruling", "控制": "control",
"服从": "submission", "屈服": "yielding", "顺从": "obedient",
"奴隶": "slave", "奴": "slave", "宠物": "pet",
"主人": "master", "主": "master", "女王": "queen",
"女主": "mistress", "王": "king", "君主": "sovereign",
// 强度描述
"轻柔": "gentle", "温和": "mild", "激烈": "intense",
"粗暴": "rough", "野蛮": "savage", "狂野": "wild",
"疯狂": "crazy", "极端": "extreme", "过分": "excessive"
},
intimate_settings: {
// 私密场所
"床": "bed", "床上": "on bed", "大床": "big bed",
"单人床": "single bed", "双人床": "double bed", "水床": "waterbed",
"床单": "bedsheet", "被子": "blanket", "枕头": "pillow",
"被窝": "under blanket", "毯子": "blanket", "软垫": "soft mat",
// 卧室环境
"卧室": "bedroom", "主卧": "master bedroom", "客房": "guest room",
"宿舍": "dormitory", "公寓": "apartment", "套房": "suite",
"酒店房间": "hotel room", "民宿": "bed and breakfast",
// 浴室场所
"浴室": "bathroom", "洗手间": "bathroom", "淋浴间": "shower room",
"浴缸": "bathtub", "按摩浴缸": "jacuzzi", "淋浴": "shower",
"蒸汽浴": "steam bath", "桑拿": "sauna", "温泉": "hot spring",
// 客厅家具
"沙发": "sofa", "长沙发": "couch", "皮沙发": "leather sofa",
"躺椅": "recliner", "懒人椅": "lazy chair", "摇椅": "rocking chair",
"地毯": "carpet", "地垫": "mat", "地板": "floor",
"茶几": "coffee table", "边桌": "side table",
// 其他家具
"桌子": "table", "书桌": "desk", "梳妆台": "dressing table",
"椅子": "chair", "办公椅": "office chair", "吧台椅": "bar stool",
"墙": "wall", "墙角": "corner", "窗台": "windowsill",
"阳台": "balcony", "露台": "terrace", "天台": "rooftop",
// 交通工具
"车里": "in car", "后座": "back seat", "驾驶座": "driver seat",
"副驾驶": "passenger seat", "货车": "truck", "面包车": "van",
"火车": "train", "飞机": "airplane", "游艇": "yacht",
// 户外场所
"野外": "outdoors", "森林": "forest", "树林": "woods",
"海滩": "beach", "沙滩": "sandy beach", "海边": "seaside",
"草地": "grassland", "花园": "garden", "公园": "park",
"山顶": "mountain top", "山洞": "cave", "帐篷": "tent",
// 特殊场所
"办公室": "office", "会议室": "meeting room", "储藏室": "storage room",
"教室": "classroom", "图书馆": "library", "实验室": "laboratory",
"厕所": "toilet", "洗手间": "restroom", "更衣室": "changing room",
"试衣间": "fitting room", "化妆间": "dressing room",
"健身房": "gym", "瑜伽室": "yoga room", "舞蹈室": "dance studio",
// 住宿场所
"酒店": "hotel", "旅馆": "motel", "民宿": "guesthouse",
"度假村": "resort", "别墅": "villa", "小屋": "cabin",
"招待所": "hostel", "青旅": "youth hostel"
},
fetish_categories: {
// 服装恋物
"丝袜": "stockings", "黑丝": "black stockings", "白丝": "white stockings",
"连裤袜": "pantyhose", "网袜": "fishnet stockings", "过膝袜": "thigh highs",
"高跟鞋": "high heels", "靴子": "boots", "长靴": "knee boots",
"制服": "uniform", "学生装": "school uniform", "护士装": "nurse outfit",
"女仆装": "maid outfit", "空姐装": "flight attendant uniform",
// 材质恋物
"蕾丝": "lace", "真丝": "silk", "缎子": "satin",
"皮革": "leather", "乳胶": "latex", "橡胶": "rubber",
"PVC": "pvc", "金属": "metal", "链条": "chain",
// 束缚用具
"束缚": "bondage", "绳子": "rope", "绳索": "rope",
"手铐": "handcuffs", "脚镣": "shackles", "锁链": "chains",
"眼罩": "blindfold", "口球": "gag", "项圈": "collar",
"皮带": "belt", "背带": "harness", "束身衣": "corset",
// 调教用具
"鞭子": "whip", "皮鞭": "leather whip", "马鞭": "riding crop",
"板子": "paddle", "藤条": "cane", "羽毛": "feather",
"蜡烛": "candle", "蜡油": "wax", "冰块": "ice",
"夹子": "clamps", "乳夹": "nipple clamps", "刑具": "torture device",
// 情趣用品
"玩具": "toy", "按摩棒": "vibrator", "震动棒": "vibrator",
"假阳具": "dildo", "双头龙": "double dildo", "仿真器": "realistic toy",
"跳蛋": "bullet vibrator", "遥控器": "remote control", "震动器": "vibrator",
"肛塞": "butt plug", "前列腺": "prostate massager", "扩张器": "dilator",
"充气娃娃": "sex doll", "飞机杯": "masturbator", "倒模": "pocket pussy",
// 特殊恋物
"触手": "tentacle", "怪物": "monster", "野兽": "beast",
"异形": "alien", "机器人": "robot", "人偶": "doll",
"机器": "machine", "机械": "mechanical", "人工": "artificial",
"科技": "technology", "虚拟": "virtual", "全息": "holographic",
// 材质特殊
"毛绒": "fur", "羽毛": "feather", "丝绸": "silk",
"天鹅绒": "velvet", "绒毛": "fuzzy", "光滑": "smooth",
"粗糙": "rough", "硬质": "hard", "软质": "soft"
},
body_modifications: {
// 纹身类型
"纹身": "tattoo", "刺青": "tattoo", "花臂": "sleeve tattoo",
"图腾": "tribal tattoo", "文字": "text tattoo", "图案": "pattern tattoo",
"彩绘": "body painting", "临时纹身": "temporary tattoo",
"传统纹身": "traditional tattoo", "日式纹身": "japanese tattoo",
// 穿孔类型
"穿孔": "piercing", "打洞": "piercing", "耳洞": "ear piercing",
"鼻环": "nose ring", "唇环": "lip ring", "舌环": "tongue piercing",
"肚脐环": "navel piercing", "乳环": "nipple piercing",
"私处穿孔": "genital piercing", "眉环": "eyebrow piercing",
// 自然标记
"疤痕": "scar", "伤疤": "scar", "刀疤": "knife scar",
"胎记": "birthmark", "痣": "mole", "黑痣": "dark mole",
"雀斑": "freckles", "斑点": "spots", "色斑": "pigmentation",
"美人痣": "beauty mark", "泪痣": "tear mole",
// 肌肉特征
"肌肉": "muscle", "腹肌": "abs", "六块腹肌": "six pack",
"八块腹肌": "eight pack", "人鱼线": "v-line", "马甲线": "ab line",
"肱二头肌": "biceps", "胸肌": "pectoral muscles", "背肌": "back muscles",
"臀肌": "glutes", "大腿肌": "thigh muscles", "小腿肌": "calf muscles",
// 骨骼特征
"锁骨": "collarbone", "肩胛骨": "shoulder blade", "脊椎": "spine",
"肋骨": "ribs", "髋骨": "hip bone", "颧骨": "cheekbone",
"下颌": "jawline", "尖下巴": "pointed chin", "方下巴": "square jaw",
// 身体凹陷
"腰窝": "dimples", "酒窝": "dimples", "梨涡": "dimples",
"锁骨窝": "collarbone hollow", "太阳穴": "temples",
"颈窝": "neck hollow", "脚踝窝": "ankle hollow",
// 特殊特征
"虎牙": "fangs", "小虎牙": "small fangs", "门牙": "front teeth",
"双眼皮": "double eyelids", "单眼皮": "single eyelids",
"卧蚕": "aegyo sal", "眼袋": "eye bags", "鱼尾纹": "crow's feet",
"法令纹": "nasolabial folds", "颈纹": "neck lines"
},
clothing_states: {
// 脱衣状态
"裸体": "nude", "全裸": "completely nude", "一丝不挂": "stark naked",
"半裸": "topless", "上身裸体": "topless", "下身裸体": "bottomless",
"微露": "slightly exposed", "若隐若现": "faintly visible",
// 穿着状态
"穿戴整齐": "fully dressed", "衣冠楚楚": "well-dressed",
"衣衫不整": "disheveled", "衣不蔽体": "barely clothed",
"衣衫褴褛": "ragged clothes", "破烂": "tattered",
// 材质状态
"透明": "transparent", "半透明": "see-through", "透视": "see-through",
"薄": "thin", "厚": "thick", "轻薄": "light",
"厚重": "heavy", "柔软": "soft", "粗糙": "rough",
"光滑": "smooth", "有光泽": "glossy", "无光": "matte",
// 合身程度
"紧身": "tight", "贴身": "form-fitting", "修身": "slim-fit",
"宽松": "loose", "肥大": "oversized", "合身": "well-fitted",
"过大": "too big", "过小": "too small", "刚好": "just right",
// 长度状态
"短": "short", "超短": "very short", "迷你": "mini",
"长": "long", "超长": "very long", "及地": "floor-length",
"中等": "medium", "标准": "standard", "正常": "normal",
// 暴露程度
"露": "exposed", "露出": "showing", "展示": "displaying",
"暴露": "revealing", "性感": "sexy", "保守": "conservative",
"大胆": "bold", "开放": "open", "含蓄": "modest",
"若隐若现": "peek-a-boo", "欲盖弥彰": "teasingly covered",
// 穿脱动作
"脱": "undressing", "脱下": "taking off", "褪去": "removing",
"穿": "dressing", "穿上": "putting on", "套": "slipping on",
"换": "changing", "更衣": "changing clothes", "试穿": "trying on",
"扯": "pulling", "撕": "tearing", "剪": "cutting",
// 衣物状态
"破": "torn", "破洞": "holes", "开口": "opening",
"裂缝": "crack", "撕裂": "ripped", "磨损": "worn",
"湿": "wet", "潮湿": "damp", "浸湿": "soaked",
"干": "dry", "干燥": "dried", "干净": "clean",
"脏": "dirty", "污": "stained", "染色": "colored",
"乱": "messy", "凌乱": "disheveled", "整齐": "neat",
"皱": "wrinkled", "平整": "smooth", "熨烫": "ironed"
},
romance_keywords: {
// 关系称谓
"恋人": "lovers", "情侣": "couple", "爱侣": "lovers",
"男友": "boyfriend", "女友": "girlfriend", "伴侣": "partner",
"爱人": "lover", "心上人": "sweetheart", "意中人": "beloved",
"真爱": "true love", "挚爱": "beloved", "最爱": "favorite",
// 恋爱类型
"初恋": "first love", "暗恋": "crush", "单恋": "unrequited love",
"热恋": "passionate love", "苦恋": "painful love", "禁恋": "forbidden love",
"师生恋": "teacher-student romance", "办公室恋情": "office romance",
"远距离恋爱": "long distance relationship", "网恋": "online romance",
// 情感状态
"心动": "heartbeat", "怦然心动": "heart racing", "一见钟情": "love at first sight",
"脸红心跳": "blushing", "心跳加速": "racing heart", "心如鹿撞": "heart pounding",
"心花怒放": "heart blooming", "心潮澎湃": "surging emotions",
"情不自禁": "can't help oneself", "难以自拔": "unable to extricate",
// 甜蜜情感
"甜蜜": "sweet", "温馨": "warm", "浪漫": "romantic",
"幸福": "happy", "快乐": "joyful", "满足": "satisfied",
"陶醉": "intoxicated", "沉醉": "drunk with love", "痴迷": "infatuated",
"甜腻": "sickeningly sweet", "蜜糖": "honey", "糖分": "sweetness",
// 思念情感
"想念": "missing", "思念": "longing", "牵挂": "caring",
"惦记": "thinking of", "念念不忘": "unforgettable", "朝思暮想": "thinking day and night",
"魂牵梦绕": "haunting dreams", "日思夜想": "thinking constantly",
"相思": "lovesickness", "离愁": "separation sorrow",
// 嫉妒情感
"嫉妒": "jealous", "吃醋": "jealous", "争风吃醋": "jealous rivalry",
"醋意": "jealousy", "占有欲": "possessiveness", "独占": "monopolize",
"不安": "unease", "担心": "worry", "猜疑": "suspicion",
// 分合状态
"表白": "confession", "告白": "confession", "求爱": "courtship",
"追求": "pursuit", "示爱": "showing love", "求婚": "proposal",
"订婚": "engagement", "结婚": "marriage", "蜜月": "honeymoon",
"分手": "breakup", "分离": "separation", "离别": "parting",
"复合": "reunion", "和好": "reconcile", "重归于好": "getting back together",
// 亲密行为
"约会": "dating", "约会": "date", "幽会": "rendezvous",
"散步": "walk together", "看电影": "watch movie", "吃饭": "dinner date",
"牵手": "holding hands", "拥抱": "hugging", "接吻": "kissing",
"依偎": "cuddling", "偎依": "snuggling", "相拥": "embracing",
// 情话表达
"情话": "love words", "甜言蜜语": "sweet words", "告白": "confession",
"承诺": "promise", "誓言": "vow", "山盟海誓": "eternal vow",
"海枯石烂": "until seas dry", "天长地久": "everlasting",
"白头偕老": "grow old together", "永结同心": "united forever",
// 情感深度
"深爱": "deep love", "挚爱": "cherished love", "痴情": "devoted love",
"专情": "faithful love", "深情": "deep affection", "真情": "true feelings",
"纯情": "pure love", "真心": "sincere heart", "诚意": "sincerity",
"用心": "heartfelt", "全心全意": "wholeheartedly", "一心一意": "single-minded"
},
emotional_states: {
// 欲望相关
"欲望": "desire", "渴望": "longing", "冲动": "impulse",
"饥渴": "thirsty", "急需": "desperate", "迫切": "urgent",
"强烈": "intense", "炽热": "burning", "火热": "passionate",
"狂野": "wild", "疯狂": "crazy", "失控": "out of control",
// 兴奋状态
"兴奋": "excited", "激动": "aroused", "亢奋": "euphoric",
"刺激": "stimulation", "快感": "pleasure", "爽": "pleasurable",
"舒服": "comfortable", "畅快": "exhilarating", "痛快": "satisfying",
"过瘾": "addictive", "上瘾": "addicted", "沉迷": "obsessed",
// 满足状态
"满足": "satisfied", "充实": "fulfilled", "完整": "complete",
"愉悦": "pleasure", "快乐": "joy", "幸福": "happiness",
"陶醉": "intoxicated", "沉醉": "drunk", "迷醉": "enchanted",
"销魂": "ecstatic", "飘飘然": "floating", "如痴如醉": "mesmerized",
// 紧张焦虑
"紧张": "nervous", "不安": "anxious", "忐忑": "restless",
"慌张": "flustered", "手足无措": "at a loss", "局促": "awkward",
"窘迫": "embarrassed", "尴尬": "awkward", "难堪": "mortified",
"焦虑": "anxious", "担忧": "worried", "忧虑": "concerned",
// 期待好奇
"期待": "anticipation", "盼望": "looking forward", "向往": "yearning",
"好奇": "curious", "感兴趣": "interested", "想知道": "wondering",
"探索": "exploration", "发现": "discovery", "新奇": "novelty",
"惊喜": "surprise", "意外": "unexpected", "震撼": "shocking",
// 羞耻害羞
"羞耻": "shame", "羞愧": "ashamed", "惭愧": "guilty",
"不好意思": "embarrassed", "难为情": "shy", "脸红": "blushing",
"害羞": "shy", "腼腆": "bashful", "扭捏": "coy",
"矜持": "reserved", "含蓄": "modest", "内敛": "introverted",
// 大胆主动
"大胆": "bold", "勇敢": "brave", "无畏": "fearless",
"主动": "proactive", "积极": "active", "进取": "aggressive",
"直接": "direct", "坦率": "frank", "开放": "open",
"放得开": "uninhibited", "豪放": "unrestrained", "奔放": "wild",
// 被动顺从
"被动": "passive", "消极": "negative", "退缩": "withdrawn",
"顺从": "submissive", "听话": "obedient", "乖巧": "well-behaved",
"温顺": "docile", "柔顺": "gentle", "配合": "cooperative",
"依赖": "dependent", "依恋": "attached", "粘人": "clingy",
// 反抗挣扎
"反抗": "resistant", "抗拒": "resisting", "反对": "opposing",
"挣扎": "struggling", "反抗": "rebelling", "违抗": "defying",
"拒绝": "refusing", "推辞": "declining", "回避": "avoiding",
"逃避": "escaping", "躲避": "hiding", "闪躲": "dodging",
// 情感波动
"矛盾": "conflicted", "纠结": "tangled", "复杂": "complicated",
"混乱": "confused", "迷茫": "lost", "困惑": "puzzled",
"犹豫": "hesitant", "踌躇": "hesitating", "不决": "undecided",
"摇摆": "wavering", "动摇": "shaken", "不定": "unstable"
}
};
let isProcessing = false;
let currentProgressButton = null;
let processedMessages = new Map();
let currentImageUrl = null;
let currentSettings = null;
let lastScreenSize = null;
function getCurrentScreenSize() {
return window.innerWidth <= 1000 ? 'small' : 'large';
}
function handleWindowResize() {
if (!isActive()) return;
const currentScreenSize = getCurrentScreenSize();
if (lastScreenSize && lastScreenSize !== currentScreenSize && currentImageUrl && currentSettings) {
$('#wallhaven-app-background, #wallhaven-chat-background').remove();
$('#wallhaven-app-overlay, #wallhaven-chat-overlay').remove();
applyBackgroundToApp(currentImageUrl, currentSettings);
}
lastScreenSize = currentScreenSize;
}
function clearBackgroundState() {
document.querySelectorAll('[id^="wallhaven-"]').forEach(el => el.remove());
currentImageUrl = null;
currentSettings = null;
lastScreenSize = null;
}
function getWallhavenSettings() {
if (!extension_settings[EXT_ID].wallhavenBackground) {
extension_settings[EXT_ID].wallhavenBackground = structuredClone(defaultSettings);
}
const settings = extension_settings[EXT_ID].wallhavenBackground;
for (const key in defaultSettings) {
if (settings[key] === undefined) {
settings[key] = defaultSettings[key];
}
}
return settings;
}
function isActive() {
if (!window.isXiaobaixEnabled) return false;
const settings = getWallhavenSettings();
return settings.enabled;
}
function isLandscapeOrientation() {
return window.innerWidth > window.innerHeight;
}
function getRatiosForOrientation() {
if (isLandscapeOrientation()) {
return "16x9,16x10,21x9";
} else {
return "9x16,10x16,1x1,9x18";
}
}
function showProgressInMessageHeader(messageElement, text) {
const flexContainer = messageElement.querySelector('.flex-container.flex1.alignitemscenter');
if (!flexContainer) return null;
removeProgressFromMessageHeader();
const progressButton = document.createElement('div');
progressButton.className = 'mes_btn wallhaven_progress_indicator';
progressButton.style.cssText = `
color: #007acc !important;
cursor: default !important;
font-size: 11px !important;
padding: 2px 6px !important;
opacity: 0.9;
`;
progressButton.innerHTML = `<i class="fa-solid fa-spinner fa-spin" style="margin-right: 4px;"></i>${text}`;
progressButton.title = '正在为消息生成配图...';
flexContainer.appendChild(progressButton);
currentProgressButton = progressButton;
return progressButton;
}
function updateProgressText(text) {
if (currentProgressButton) {
currentProgressButton.innerHTML = `<i class="fa-solid fa-spinner fa-spin" style="margin-right: 4px;"></i>${text}`;
}
}
function removeProgressFromMessageHeader() {
if (currentProgressButton) {
currentProgressButton.remove();
currentProgressButton = null;
}
document.querySelectorAll('.wallhaven_progress_indicator').forEach(el => el.remove());
}
function renderCustomTagsList() {
const settings = getWallhavenSettings();
const container = document.getElementById('wallhaven_custom_tags_list');
if (!container) return;
container.innerHTML = '';
if (!settings.customTags || settings.customTags.length === 0) {
container.innerHTML = '<div class="custom-tags-empty">暂无自定义标签</div>';
return;
}
settings.customTags.forEach(tag => {
const tagElement = document.createElement('div');
tagElement.className = 'custom-tag-item';
tagElement.innerHTML = `
<span class="custom-tag-text">${tag}</span>
<span class="custom-tag-remove" data-tag="${tag}">×</span>
`;
container.appendChild(tagElement);
});
container.querySelectorAll('.custom-tag-remove').forEach(btn => {
btn.addEventListener('click', function() {
removeCustomTag(this.dataset.tag);
});
});
}
function addCustomTag(tag) {
if (!tag || !tag.trim()) return;
tag = tag.trim().toLowerCase();
const settings = getWallhavenSettings();
if (!settings.customTags) {
settings.customTags = [];
}
if (settings.customTags.includes(tag)) {
return false;
}
settings.customTags.push(tag);
saveSettingsDebounced();
renderCustomTagsList();
return true;
}
function removeCustomTag(tag) {
const settings = getWallhavenSettings();
if (!settings.customTags) return;
const index = settings.customTags.indexOf(tag);
if (index > -1) {
settings.customTags.splice(index, 1);
saveSettingsDebounced();
renderCustomTagsList();
}
}
function extractTagsFromText(text, isBgMode = false) {
const settings = getWallhavenSettings();
const customTagObjs = (settings.customTags || []).map(tag => ({
tag: tag,
category: 'custom',
weight: tagWeights.custom,
position: text.lastIndexOf(tag)
}));
if (isBgMode) {
const bgCategories = ['locations', 'weather_time', 'objects'];
const tagsByCategory = {};
bgCategories.forEach(category => {
tagsByCategory[category] = [];
if (wallhavenTags[category]) {
Object.entries(wallhavenTags[category]).forEach(([chinese, english]) => {
const lastPos = text.lastIndexOf(chinese);
if (lastPos !== -1) {
tagsByCategory[category].push({
tag: english,
category: category,
weight: tagWeights[category] || 1,
position: lastPos,
chinese: chinese
});
}
});
}
});
const selectedTags = [...customTagObjs];
Object.entries(tagsByCategory).forEach(([category, tags]) => {
if (tags.length === 0) return;
tags.sort((a, b) => b.position - a.position);
const selectedFromCategory = tags.slice(0, 1);
selectedFromCategory.forEach(tagObj => {
selectedTags.push({
tag: tagObj.tag,
category: tagObj.category,
weight: tagObj.weight
});
});
});
if (selectedTags.length === customTagObjs.length) {
selectedTags.push({ tag: 'landscape', category: 'background_fallback', weight: 1 });
}
return { tags: selectedTags };
} else {
const tagsByCategory = {};
Object.keys(wallhavenTags).forEach(category => {
tagsByCategory[category] = [];
Object.entries(wallhavenTags[category]).forEach(([chinese, english]) => {
const lastPos = text.lastIndexOf(chinese);
if (lastPos !== -1) {
tagsByCategory[category].push({
tag: english,
category: category,
weight: tagWeights[category] || 1,
position: lastPos,
chinese: chinese
});
}
});
});
const selectedTags = [...customTagObjs];
Object.entries(tagsByCategory).forEach(([category, tags]) => {
if (tags.length === 0) return;
tags.sort((a, b) => b.position - a.position);
let maxCount = 1;
if (['characters', 'clothing', 'body_features'].includes(category)) {
maxCount = 2;
}
const selectedFromCategory = tags.slice(0, maxCount);
selectedFromCategory.forEach(tagObj => {
selectedTags.push({
tag: tagObj.tag,
category: tagObj.category,
weight: tagObj.weight
});
});
});
return { tags: selectedTags };
}
}
async function fetchWithCFWorker(targetUrl) {
const cfWorkerUrl = 'https://wallhaven.velure.top/?url=';
const finalUrl = cfWorkerUrl + encodeURIComponent(targetUrl);
const response = await fetch(finalUrl);
if (!response.ok) {
throw new Error(`CF Worker请求失败: HTTP ${response.status} - ${response.statusText}`);
}
return response;
}
async function searchSingleTag(tagObj, category, purity, isBgMode) {
let searchTag = tagObj.tag;
if (isBgMode) {
searchTag = `${tagObj.tag} -girl -male -people -anime`;
}
const ratios = getRatiosForOrientation();
const wallhavenUrl = `https://wallhaven.cc/api/v1/search?q=${encodeURIComponent(searchTag)}&categories=${category}&purity=${purity}&ratios=${ratios}&sorting=favorites&page=1&`;
try {
const response = await fetchWithCFWorker(wallhavenUrl);
const data = await response.json();
return {
tagObj: tagObj,
success: true,
total: data.meta.total,
images: data.data || []
};
} catch (error) {
return {
tagObj: tagObj,
success: false,
error: error.message,
total: 0,
images: []
};
}
}
async function intelligentTagMatching(tagObjs, settings) {
if (!tagObjs || tagObjs.length === 0) {
throw new Error('没有可用的标签');
}
const allImages = new Map();
for (let i = 0; i < tagObjs.length; i++) {
if (!isActive()) {
throw new Error('功能已禁用');
}
const tagObj = tagObjs[i];
const isCustom = tagObj.category === 'custom' ? '[自定义]' : '';
updateProgressText(`搜索 ${i + 1}/${tagObjs.length}: ${isCustom}${tagObj.tag} (权重${tagObj.weight})`);
const result = await searchSingleTag(tagObj, settings.category, settings.purity, settings.bgMode);
if (result.success) {
result.images.forEach(img => {
if (!allImages.has(img.id)) {
allImages.set(img.id, {
...img,
matchedTags: [tagObj],
weightedScore: tagObj.weight
});
} else {
const existingImg = allImages.get(img.id);
existingImg.matchedTags.push(tagObj);
existingImg.weightedScore += tagObj.weight;
}
});
}
if (i < tagObjs.length - 1) {
await new Promise(resolve => setTimeout(resolve, 500));
}
}
const allImagesArray = Array.from(allImages.values());
if (allImagesArray.length === 0) {
throw new Error('所有标签都没有找到匹配的图片');
}
allImagesArray.sort((a, b) => {
if (b.weightedScore !== a.weightedScore) {
return b.weightedScore - a.weightedScore;
}
return b.favorites - a.favorites;
});
const maxWeightedScore = allImagesArray[0].weightedScore;
const bestMatches = allImagesArray.filter(img => img.weightedScore === maxWeightedScore);
const randomIndex = Math.floor(Math.random() * bestMatches.length);
return bestMatches[randomIndex];
}
function applyMessageStyling() {
const mesElements = document.querySelectorAll('#chat .mes:not([data-wallhaven-styled])');
mesElements.forEach(mes => {
mes.style.cssText += `
backdrop-filter: none !important;
-webkit-backdrop-filter: none !important;
background-color: transparent !important;
box-shadow: none !important;
position: relative !important;
z-index: 1002 !important;
`;
mes.setAttribute('data-wallhaven-styled', 'true');
});
const mesTextElements = document.querySelectorAll('#chat .mes_text:not([data-wallhaven-text-styled])');
mesTextElements.forEach(mesText => {
mesText.style.cssText += `
text-shadow: rgba(0, 0, 0, 0.8) 1px 1px 2px !important;
color: inherit !important;
position: relative !important;
z-index: 1003 !important;
`;
mesText.setAttribute('data-wallhaven-text-styled', 'true');
});
const messageElements = document.querySelectorAll('#chat .mes, #chat .mes_text, #chat .name, #chat .mes_img, #chat .mes_avatar, #chat .mes_btn');
messageElements.forEach(element => {
if (element && !element.hasAttribute('data-wallhaven-z-styled')) {
element.style.cssText += `
position: relative !important;
z-index: 1002 !important;
`;
element.setAttribute('data-wallhaven-z-styled', 'true');
}
});
}
function applyBackgroundToApp(imageUrl, settings) {
currentImageUrl = imageUrl;
currentSettings = { ...settings };
lastScreenSize = getCurrentScreenSize();
const isSmallScreen = window.innerWidth <= 1000;
if (isSmallScreen) {
const chatElement = document.getElementById('chat');
if (!chatElement) return;
const bgId = 'wallhaven-mobile-background';
const overlayId = 'wallhaven-mobile-overlay';
document.querySelectorAll('[id^="wallhaven-"]').forEach(el => el.remove());
let topOffset = 0;
const rightNavHolder = document.getElementById('rightNavHolder');
if (rightNavHolder) {
const rect = rightNavHolder.getBoundingClientRect();
topOffset = rect.bottom;
} else {
topOffset = 50;
}
let backgroundContainer = document.getElementById(bgId);
let overlay = document.getElementById(overlayId);
if (!backgroundContainer) {
backgroundContainer = document.createElement('div');
backgroundContainer.id = bgId;
backgroundContainer.style.cssText = `
position: fixed !important;
top: ${topOffset}px !important;
left: 0 !important;
right: 0 !important;
bottom: 0 !important;
width: 100vw !important;
height: calc(100vh - ${topOffset}px) !important;
background-size: 100% auto !important;
background-position: top center !important;
background-repeat: no-repeat !important;
z-index: -1 !important;
pointer-events: none !important;
overflow: hidden !important;
`;
document.body.appendChild(backgroundContainer);
}
if (!overlay) {
overlay = document.createElement('div');
overlay.id = overlayId;
overlay.style.cssText = `
position: fixed !important;
top: ${topOffset}px !important;
left: 0 !important;
right: 0 !important;
bottom: 0 !important;
width: 100vw !important;
height: calc(100vh - ${topOffset}px) !important;
background-color: rgba(0, 0, 0, ${settings.opacity}) !important;
z-index: 0 !important;
pointer-events: none !important;
overflow: hidden !important;
`;
document.body.appendChild(overlay);
}
backgroundContainer.style.backgroundImage = `url("${imageUrl}")`;
overlay.style.backgroundColor = `rgba(0, 0, 0, ${settings.opacity})`;
backgroundContainer.style.top = `${topOffset}px`;
backgroundContainer.style.height = `calc(100vh - ${topOffset}px)`;
overlay.style.top = `${topOffset}px`;
overlay.style.height = `calc(100vh - ${topOffset}px)`;
if (chatElement) {
chatElement.style.cssText += `
background-color: transparent !important;
background-image: none !important;
background: transparent !important;
position: relative !important;
z-index: 1 !important;
backdrop-filter: none !important;
-webkit-backdrop-filter: none !important;
`;
}
applyMessageStyling();
} else {
const targetContainer = document.getElementById('expression-wrapper');
if (!targetContainer) return;
const bgId = 'wallhaven-app-background';
const overlayId = 'wallhaven-app-overlay';
let backgroundContainer = document.getElementById(bgId);
let overlay = document.getElementById(overlayId);
if (!backgroundContainer) {
backgroundContainer = document.createElement('div');
backgroundContainer.id = bgId;
backgroundContainer.style.cssText = `
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-size: 100% auto;
background-position: top center;
background-repeat: no-repeat;
z-index: 1;
pointer-events: none;
`;
targetContainer.insertBefore(backgroundContainer, targetContainer.firstChild);
}
if (!overlay) {
overlay = document.createElement('div');
overlay.id = overlayId;
overlay.style.cssText = `
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, ${settings.opacity});
z-index: 2;
pointer-events: none;
`;
targetContainer.insertBefore(overlay, targetContainer.firstChild);
}
backgroundContainer.style.backgroundImage = `url("${imageUrl}")`;
overlay.style.backgroundColor = `rgba(0, 0, 0, ${settings.opacity})`;
targetContainer.style.position = 'relative';
const chatElement = document.getElementById('chat');
if (chatElement) {
chatElement.style.cssText += `
background-color: transparent !important;
background-image: none !important;
background: transparent !important;
position: relative;
z-index: 3;
backdrop-filter: none !important;
-webkit-backdrop-filter: none !important;
box-shadow: none !important;
border: none !important;
text-shadow: none !important;
opacity: 1 !important;
`;
}
applyMessageStyling();
}
}
function isMessageComplete(messageElement) {
const regenerateBtn = messageElement.querySelector('.mes_regenerate');
const editBtn = messageElement.querySelector('.mes_edit');
const hasButtons = regenerateBtn || editBtn;
const mesText = messageElement.querySelector('.mes_text');
const hasContent = mesText && mesText.textContent.trim().length > 0;
const hasStreamingIndicator = messageElement.querySelector('.typing_indicator') ||
messageElement.querySelector('.mes_loading') ||
messageElement.classList.contains('streaming');
return hasButtons && hasContent && !hasStreamingIndicator;
}
function getContentHash(text) {
let hash = 0;
if (text.length === 0) return hash;
for (let i = 0; i < text.length; i++) {
const char = text.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
hash = hash & hash;
}
return hash.toString();
}
function shouldProcessMessage(messageId, messageText) {
const contentHash = getContentHash(messageText);
const storedHash = processedMessages.get(messageId);
return !storedHash || storedHash !== contentHash;
}
function markMessageProcessed(messageId, messageText) {
const contentHash = getContentHash(messageText);
processedMessages.set(messageId, contentHash);
}
async function handleAIMessage(data) {
if (!isActive() || isProcessing) return;
try {
isProcessing = true;
const messageId = data.messageId || data;
if (!messageId) return;
const messageElement = document.querySelector(`div.mes[mesid="${messageId}"]`);
if (!messageElement || messageElement.classList.contains('is_user')) return;
let retryCount = 0;
const maxRetries = 10;
while (retryCount < maxRetries) {
if (isMessageComplete(messageElement)) {
break;
}
retryCount++;
await new Promise(resolve => setTimeout(resolve, 1000));
if (!isActive()) return;
}
const mesText = messageElement.querySelector('.mes_text');
if (!mesText) return;
const messageText = mesText.textContent || '';
if (!messageText.trim() || messageText.length < 10) return;
if (!shouldProcessMessage(messageId, messageText)) {
return;
}
markMessageProcessed(messageId, messageText);
const settings = getWallhavenSettings();
showProgressInMessageHeader(messageElement, '提取标签中...');
const result = extractTagsFromText(messageText, settings.bgMode);
if (result.tags.length === 0) {
updateProgressText('未提取到标签');
setTimeout(removeProgressFromMessageHeader, 2000);
return;
}
if (!isActive()) return;
const orientation = isLandscapeOrientation() ? '横屏' : '竖屏';
const modeText = settings.bgMode ? '背景' : '角色';
const totalWeight = result.tags.reduce((sum, tagObj) => sum + tagObj.weight, 0);
const customCount = result.tags.filter(t => t.category === 'custom').length;
updateProgressText(`${orientation}${modeText}:提取到 ${result.tags.length} 个标签 (自定义${customCount}个,总权重${totalWeight})`);
await new Promise(resolve => setTimeout(resolve, 500));
if (!isActive()) return;
const selectedImage = await intelligentTagMatching(result.tags, settings);
if (!isActive()) return;
updateProgressText('应用背景中...');
const imageUrl = `https://wallhaven.velure.top/?url=${encodeURIComponent(selectedImage.path)}`;
applyBackgroundToApp(imageUrl, settings);
const coreTagsCount = selectedImage.matchedTags.filter(t => t.weight >= 2).length;
const customMatchCount = selectedImage.matchedTags.filter(t => t.category === 'custom').length;
updateProgressText(`${modeText}配图完成! 核心匹配${coreTagsCount}个 自定义${customMatchCount}个 权重${selectedImage.weightedScore}`);
setTimeout(removeProgressFromMessageHeader, 2000);
} catch (error) {
updateProgressText(`配图失败: ${error.message.length > 20 ? error.message.substring(0, 20) + '...' : error.message}`);
setTimeout(removeProgressFromMessageHeader, 3000);
} finally {
isProcessing = false;
}
}
function updateSettingsControls() {
const settings = getWallhavenSettings();
$('#wallhaven_enabled').prop('checked', settings.enabled);
$('#wallhaven_bg_mode').prop('checked', settings.bgMode);
$('#wallhaven_category').val(settings.category);
$('#wallhaven_purity').val(settings.purity);
$('#wallhaven_opacity').val(settings.opacity);
$('#wallhaven_opacity_value').text(Math.round(settings.opacity * 100) + '%');
// 控制后续设置的显示/隐藏
const settingsContainer = $('#wallhaven_settings_container');
if (settings.enabled) {
settingsContainer.show();
} else {
settingsContainer.hide();
}
renderCustomTagsList();
}
function initSettingsEvents() {
$('#wallhaven_enabled').off('change').on('change', function() {
if (!window.isXiaobaixEnabled) return;
const settings = getWallhavenSettings();
const wasEnabled = settings.enabled;
settings.enabled = $(this).prop('checked');
saveSettingsDebounced();
// 控制后续设置的显示/隐藏
const settingsContainer = $('#wallhaven_settings_container');
if (settings.enabled) {
settingsContainer.show();
} else {
settingsContainer.hide();
}
if (settings.enabled && !wasEnabled) {
bindMessageHandlers();
} else if (!settings.enabled && wasEnabled) {
clearBackgroundState();
removeProgressFromMessageHeader();
processedMessages.clear();
isProcessing = false;
unbindMessageHandlers();
}
});
$('#wallhaven_bg_mode').off('change').on('change', function() {
if (!window.isXiaobaixEnabled) return;
const settings = getWallhavenSettings();
settings.bgMode = $(this).prop('checked');
saveSettingsDebounced();
});
$('#wallhaven_category').off('change').on('change', function() {
if (!window.isXiaobaixEnabled) return;
const settings = getWallhavenSettings();
settings.category = $(this).val();
saveSettingsDebounced();
});
$('#wallhaven_purity').off('change').on('change', function() {
if (!window.isXiaobaixEnabled) return;
const settings = getWallhavenSettings();
settings.purity = $(this).val();
saveSettingsDebounced();
});
$('#wallhaven_opacity').off('input').on('input', function() {
if (!window.isXiaobaixEnabled) return;
const settings = getWallhavenSettings();
settings.opacity = parseFloat($(this).val());
$('#wallhaven_opacity_value').text(Math.round(settings.opacity * 100) + '%');
$('#wallhaven-app-overlay, #wallhaven-chat-overlay').css('background-color', `rgba(0, 0, 0, ${settings.opacity})`);
saveSettingsDebounced();
});
$('#wallhaven_add_custom_tag').off('click').on('click', function() {
if (!window.isXiaobaixEnabled) return;
const input = document.getElementById('wallhaven_custom_tag_input');
const tag = input.value.trim();
if (tag) {
if (addCustomTag(tag)) {
input.value = '';
} else {
input.style.borderColor = '#ff6b6b';
setTimeout(() => {
input.style.borderColor = '';
}, 1000);
}
}
});
$('#wallhaven_custom_tag_input').off('keypress').on('keypress', function(e) {
if (!window.isXiaobaixEnabled) return;
if (e.which === 13) {
$('#wallhaven_add_custom_tag').click();
}
});
}
function bindMessageHandlers() {
messageEvents.cleanup();
messageEvents.on(event_types.MESSAGE_RECEIVED, handleAIMessage);
if (event_types.MESSAGE_SWIPED) {
messageEvents.on(event_types.MESSAGE_SWIPED, handleAIMessage);
}
if (event_types.MESSAGE_EDITED) {
messageEvents.on(event_types.MESSAGE_EDITED, handleAIMessage);
}
if (event_types.MESSAGE_UPDATED) {
messageEvents.on(event_types.MESSAGE_UPDATED, handleAIMessage);
}
}
function unbindMessageHandlers() {
messageEvents.cleanup();
}
function handleGlobalStateChange(event) {
const globalEnabled = event.detail.enabled;
const wallhavenControls = [
'wallhaven_enabled', 'wallhaven_bg_mode', 'wallhaven_category',
'wallhaven_purity', 'wallhaven_opacity', 'wallhaven_custom_tag_input',
'wallhaven_add_custom_tag'
];
wallhavenControls.forEach(id => {
$(`#${id}`).prop('disabled', !globalEnabled).toggleClass('disabled-control', !globalEnabled);
});
if (globalEnabled) {
updateSettingsControls();
initSettingsEvents();
if (isActive()) {
bindMessageHandlers();
}
} else {
clearBackgroundState();
removeProgressFromMessageHeader();
processedMessages.clear();
isProcessing = false;
unbindMessageHandlers();
$('#wallhaven_enabled, #wallhaven_bg_mode, #wallhaven_category, #wallhaven_purity, #wallhaven_opacity, #wallhaven_add_custom_tag').off();
$('#wallhaven_custom_tag_input').off();
}
}
function handleChatChanged() {
processedMessages.clear();
clearBackgroundState();
removeProgressFromMessageHeader();
isProcessing = false;
}
function initWallhavenBackground() {
const globalEnabled = window.isXiaobaixEnabled !== undefined ? window.isXiaobaixEnabled : true;
const wallhavenControls = [
'wallhaven_enabled', 'wallhaven_bg_mode', 'wallhaven_category',
'wallhaven_purity', 'wallhaven_opacity', 'wallhaven_custom_tag_input',
'wallhaven_add_custom_tag'
];
wallhavenControls.forEach(id => {
$(`#${id}`).prop('disabled', !globalEnabled).toggleClass('disabled-control', !globalEnabled);
});
if (globalEnabled) {
updateSettingsControls();
initSettingsEvents();
if (isActive()) {
bindMessageHandlers();
}
}
document.addEventListener('xiaobaixEnabledChanged', handleGlobalStateChange);
globalEvents.on(event_types.CHAT_CHANGED, handleChatChanged);
window.addEventListener('resize', handleWindowResize);
lastScreenSize = getCurrentScreenSize();
return { cleanup };
}
function cleanup() {
messageEvents.cleanup();
globalEvents.cleanup();
document.removeEventListener('xiaobaixEnabledChanged', handleGlobalStateChange);
window.removeEventListener('resize', handleWindowResize);
clearBackgroundState();
removeProgressFromMessageHeader();
isProcessing = false;
processedMessages.clear();
currentProgressButton = null;
currentImageUrl = null;
currentSettings = null;
}
export { initWallhavenBackground };