Skip to content

Commit f49b335

Browse files
committed
feat: 增强 Fanza 客户端并优化名称分割逻辑
2 3 本次提交包含对 Fanza 客户端和核心名称分割功能的重大改进,以及常规的数据映射更新。 4 5 主要变更: 6 7 1. **增强 Fanza 客户端 (`fanza_client.py`)** 8 * **实现双重搜索机制**:引入主搜索 (`dlsoft`) 和后备搜索 (`mono` )。当主搜索无结果时,系统会自动尝试使用后备搜索,提高了搜索成功率。 9 * **动态页面解析**:根据返回的 URL 中是否包含 `/mono/`,智能选择新旧两种不同的页面解析器,以适应 Fanza 网站不同时期的页面布局,极大增强了数据抓取的稳定性。 10 * **优化搜索过滤**:在主搜索流程中增加了对结果类型的过滤,确保只返回游戏相关的条目。 11 12 2. **优化名称分割器 (`name_splitter.py`)** 13 * **新增启发式规则**:为 `smart_split` 函数添加了新的启发式判断。当名字被分割为三部分且中间部分为单字符时(如 "アイネ・A・ロメロ"),系统会将其自动识别并合并为单个完整名称。 14 * **增强逻辑健壮性**:对上述规则增加了保护性条件,排除了 "A/B/C" 这类短名称组合被错误合并的可能。 15 * **清理例外文件**:随着新逻辑的引入,从 `name_split_exceptions.json` 中移除了不再需要的例外条目。 16 17 3. **数据维护** 18 * 更新了 Fanza 标签翻译 (`tag_fanza_to_cn.json`)。 19 * 在 Bangumi 映射中增加了对 `VNDB` 和 `ErogameScape` 的处理。
1 parent 0cb2e70 commit f49b335

File tree

7 files changed

+244
-143
lines changed

7 files changed

+244
-143
lines changed

clients/fanza_client.py

Lines changed: 182 additions & 124 deletions
Large diffs are not rendered by default.

core/name_splitter.py

Lines changed: 48 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,34 @@ def _add_exception(self, name: str):
5151
self._exceptions.add(name)
5252
logger.info(f"已在内存中将 '{name}' 标记为本次运行的例外。")
5353

54+
def _post_process_parts(self, parts: List[str]) -> List[str]:
55+
"""
56+
对分割后的部分进行后处理,自动合并 "J・さいろー" 或 "神・无月" 这样的模式。
57+
"""
58+
if len(parts) < 2:
59+
return parts
60+
61+
new_parts = []
62+
i = 0
63+
while i < len(parts):
64+
current_part = parts[i]
65+
# --- 核心改进:检查是否为任意类型的单个字符 ---
66+
if len(current_part) == 1:
67+
# 如果后面还有部分,则合并
68+
if i + 1 < len(parts):
69+
next_part = parts[i+1]
70+
merged_part = f"{current_part}{next_part}"
71+
new_parts.append(merged_part)
72+
i += 2 # 跳过下一个部分,因为它已经被合并
73+
else:
74+
# 这是最后一部分,无法合并,照常添加
75+
new_parts.append(current_part)
76+
i += 1
77+
else:
78+
new_parts.append(current_part)
79+
i += 1
80+
return new_parts
81+
5482
async def smart_split(self, text: str, interaction_provider: InteractionProvider) -> List[str]:
5583
"""
5684
智能分割名称字符串。
@@ -59,8 +87,6 @@ async def smart_split(self, text: str, interaction_provider: InteractionProvider
5987
if not text:
6088
return []
6189

62-
# --- [核心升级 3] 名称标准化 ---
63-
# 将所有内部空白(包括全角空格)统一替换为单个标准空格
6490
def normalize(name: str) -> str:
6591
return re.sub(r'\s+', ' ', name).strip()
6692

@@ -70,36 +96,42 @@ def normalize(name: str) -> str:
7096
parts = SPLIT_REGEX.split(text)
7197
cleaned_parts = [normalize(p) for p in parts if p.strip()]
7298

73-
if len(cleaned_parts) <= 1:
74-
return cleaned_parts
99+
# --- [核心升级 2] 启发式识别:处理 '名字A・名字B' 模式 ---
100+
# 如果分割结果为三部分,且中间部分为单个字符,则极有可能是完整的姓名
101+
if len(cleaned_parts) == 3 and len(cleaned_parts[1]) == 1 and (len(cleaned_parts[0]) > 1 or len(cleaned_parts[2]) > 1):
102+
logger.info(f"检测到 '名字・首字母・名字' 模式,自动合并: {text}")
103+
return [normalize(text)]
104+
105+
# 在风险识别前,先进行智能后处理
106+
processed_parts = self._post_process_parts(cleaned_parts)
107+
108+
if len(processed_parts) <= 1:
109+
return processed_parts
75110

76-
# --- [核心升级 2] 增强风险识别 ---
77-
# 规则1: 分割后出现过短的部分 (例如: 'S')
78-
is_dangerous = any(len(p) <= 1 for p in cleaned_parts)
111+
# 增强风险识别 (现在基于后处理的结果)
112+
is_dangerous = any(len(p) <= 1 for p in processed_parts)
79113

80-
# 规则2: 由'・'分割的全英文名称 (例如: 'Ryo・Lion')
81114
is_alpha_dot_split = False
82-
if not is_dangerous and '・' in text and len(cleaned_parts) > 1:
83-
if all(re.fullmatch(r'[a-zA-Z]+', p) for p in cleaned_parts):
115+
if not is_dangerous and '・' in text and len(processed_parts) > 1:
116+
if all(re.fullmatch(r'[a-zA-Z]+', p) for p in processed_parts):
84117
is_alpha_dot_split = True
85118

86119
if not is_dangerous and not is_alpha_dot_split:
87-
return cleaned_parts
120+
return processed_parts
88121

89122
# --- Interactive part ---
90-
choice = "keep" # Default action
123+
choice = "keep"
91124
save_exception = False
92125

93126
if interaction_provider:
94-
# TODO: 将增强的风险原因传递给GUI
95-
decision = await interaction_provider.get_name_split_decision(text, cleaned_parts)
127+
decision = await interaction_provider.get_name_split_decision(text, processed_parts)
96128
choice = decision.get("action", "keep")
97129
save_exception = decision.get("save_exception", False)
98130
else:
99131
# CLI Fallback
100132
def _get_input():
101133
logger.warn(f"检测到【高风险】的名称分割: '{text}'")
102-
print(f" 初步分割为: {cleaned_parts}")
134+
print(f" 初步分割为: {processed_parts}")
103135
if is_alpha_dot_split:
104136
print(" 原因: 检测到由'・'分割的纯英文名称,这可能是一个完整的名字。")
105137
else:
@@ -128,7 +160,7 @@ def _get_save_confirmation():
128160

129161
# --- Process decision ---
130162
if choice == "split":
131-
return cleaned_parts
163+
return processed_parts
132164
else: # "keep"
133165
logger.info(f"用户选择不分割 '{text}'。")
134166
if save_exception:

mapping/bangumi_ignore_list.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
[
2+
"ErogameScape",
23
"JAN番号",
34
"キャラクターチップ",
45
"下身尺寸",

mapping/bangumi_prop_mapping.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,9 @@
380380
"steam",
381381
"链接-steam"
382382
],
383+
"VNDB": [
384+
"VNDB"
385+
],
383386
"中文补丁": [
384387
"中文补丁"
385388
],

mapping/name_split_exceptions.json

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1 @@
1-
[
2-
"アイネ・A・ロメロ"
3-
]
1+
[]

mapping/tag_fanza_to_cn.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
{
22
"3P・4P": "乱交",
33
"お嬢様・令嬢": "大小姐",
4+
"くノ一": "女忍者",
45
"アイドル": "偶像",
56
"アナル": "肛交",
7+
"イチャラブ": "甜蜜恋爱",
68
"ウェイトレス": "女服务员",
79
"オナニー": "自慰",
810
"コスプレ": "角色扮演",
@@ -11,6 +13,7 @@
1113
"ツインテール": "双马尾",
1214
"ドラッグ": "药物",
1315
"ハーレム": "后宫",
16+
"バトル": "战斗",
1417
"パイズリ": "乳交",
1518
"ファンタジー": "幻想",
1619
"フェラチオ": "口交",
@@ -26,6 +29,7 @@
2629
"外国人": "外国人",
2730
"女子校生": "女学生",
2831
"女性主導": "女性主导",
32+
"女戦士": "女战士",
2933
"女教師": "女老师",
3034
"女王様": "女王",
3135
"女装・男の娘": "伪娘",
@@ -34,6 +38,7 @@
3438
"学園もの": "学校",
3539
"寝取られ(NTR)": "NTR",
3640
"巨乳": "巨乳",
41+
"巫女": "巫女",
3742
"幼なじみ": "青梅竹马",
3843
"恋愛": "恋爱",
3944
"悪堕ち": "恶堕",
@@ -47,6 +52,7 @@
4752
"濡れスケ": "湿身透视",
4853
"田舎が舞台のゲーム": "乡下",
4954
"癒されるゲーム": "治愈",
55+
"美少女": "美少女",
5056
"褐色肌": "小麦肤",
5157
"辱め": "屈辱",
5258
"野外・露出": "野外露出",

mapping/tag_mapping_dict.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,9 @@
107107
"恶堕",
108108
"堕落"
109109
],
110+
"战斗": [
111+
"战斗"
112+
],
110113
"战斗H/破衣": [
111114
"战斗H",
112115
"破衣"

0 commit comments

Comments
 (0)