Files
LittleWhiteBox/modules/wallhaven-background.js

2183 lines
97 KiB
JavaScript
Raw Normal View History

2025-12-21 01:47:38 +08:00
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 };