wangdang commited on
Commit
db9a9fd
·
verified ·
1 Parent(s): 9fd79cb

Update forwarder.py

Browse files
Files changed (1) hide show
  1. forwarder.py +132 -47
forwarder.py CHANGED
@@ -45,26 +45,20 @@ def extract_slug_from_url(url):
45
  match = re.search(r"https?://hdhive\.com/resource/(?:[^/]+/)?([a-f0-9]{32})", url, re.IGNORECASE)
46
  if match:
47
  return match.group(1)
48
- if re.fullmatch(r"[a-f0-9]{32}", url, re.IGNORECASE):
49
- return url
50
  return None
51
 
52
- def get_slug_and_target_entity(message):
53
- """返回 (slug, 目标实体),目标实体是 URL 中包含 HDHive slug 的实体"""
54
  if not message.entities:
55
- return None, None
56
  for entity in message.entities:
57
  url = None
58
  if hasattr(entity, 'url'):
59
  url = entity.url
60
- elif isinstance(entity, MessageEntityUrl) and message.text:
61
- url = message.text[entity.offset:entity.offset+entity.length]
62
  if url:
63
  slug = extract_slug_from_url(url)
64
  if slug:
65
- print(f"找到目标实体,URL: {url}, slug: {slug}")
66
- return slug, entity
67
- return None, None
68
 
69
  def get_direct_link(slug):
70
  if slug in slug_cache:
@@ -74,69 +68,160 @@ def get_direct_link(slug):
74
  if UNLOCK_PASSWORD:
75
  payload["password"] = UNLOCK_PASSWORD
76
  try:
77
- resp = requests.post(url, json=payload, timeout=10)
78
  if resp.status_code == 200:
79
  data = resp.json()
80
  if data.get("success") and data.get("link"):
81
  direct_link = data["link"]
82
  slug_cache[slug] = direct_link
83
  return direct_link
84
- elif data.get("need_password"):
85
- print(f"资源 {slug} 需要密码但未提供或密码错误")
86
- else:
87
- print(f"解锁失败: {data.get('message')}")
88
- else:
89
- print(f"API 请求失败: {resp.status_code}")
90
  except Exception as e:
91
- print(f"调用解锁 API 出错: {e}")
92
  return None
93
 
94
  async def send_modified_message(client, dest_entity, original_msg):
95
  if isinstance(original_msg, MessageService):
96
- print(f"跳过服务消息 {original_msg.id}")
97
  return
98
 
99
  if not original_msg.text:
100
  await client.forward_messages(dest_entity, original_msg)
101
- print(f"直接转发无文本消息 {original_msg.id}")
102
  return
103
 
104
- slug, target_entity = get_slug_and_target_entity(original_msg)
105
  if not slug:
106
  await client.forward_messages(dest_entity, original_msg)
107
- print(f"直接转发消息 {original_msg.id}(无 HDHive 链接)")
108
  return
109
 
110
  direct_link = get_direct_link(slug)
111
  if not direct_link:
112
  await client.forward_messages(dest_entity, original_msg)
113
- print(f"直接转发消息 {original_msg.id}(解锁失败)")
114
  return
115
 
116
- # 构造新文本:只替换目标实体对应的文本(例如“直达链接”)
117
- text = original_msg.text
118
- parts = []
119
- last = 0
120
- for entity in original_msg.entities:
121
- start = entity.offset
122
- end = start + entity.length
123
- if start > last:
124
- parts.append(text[last:start])
125
- if entity == target_entity:
126
- # 获取原实体文本(如“直达链接”)
127
- original_text = text[start:end]
128
- print(f"替换文本: '{original_text}' -> {direct_link}")
129
- parts.append(direct_link)
130
- else:
131
- parts.append(text[start:end])
132
- last = end
133
- if last < len(text):
134
- parts.append(text[last:])
135
- new_text = ''.join(parts)
136
 
137
  await client.send_message(dest_entity, new_text)
138
- print(f"已发送替换后的消息 {original_msg.id}")
139
 
140
- # 以下 forward_history, forward_new_messages, get_recent_verification_messages, main 等函数保持不变(与之前提供的完整版一致,这里为了简洁省略,但实际代码中必须包含)
141
- # 请确保您的代码中包含这些函数,我已经在之前的消息中提供过完整版本。
142
- # 由于消息长度限制,此处仅给出核心修改,实际部署时请使用我在上一条消息中给出的完整 forwarder.py 并替换其中的 send_modified_message 函数。
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  match = re.search(r"https?://hdhive\.com/resource/(?:[^/]+/)?([a-f0-9]{32})", url, re.IGNORECASE)
46
  if match:
47
  return match.group(1)
 
 
48
  return None
49
 
50
+ def get_slug_from_message(message):
 
51
  if not message.entities:
52
+ return None
53
  for entity in message.entities:
54
  url = None
55
  if hasattr(entity, 'url'):
56
  url = entity.url
 
 
57
  if url:
58
  slug = extract_slug_from_url(url)
59
  if slug:
60
+ return slug
61
+ return None
 
62
 
63
  def get_direct_link(slug):
64
  if slug in slug_cache:
 
68
  if UNLOCK_PASSWORD:
69
  payload["password"] = UNLOCK_PASSWORD
70
  try:
71
+ resp = requests.post(url, json=payload, timeout=15)
72
  if resp.status_code == 200:
73
  data = resp.json()
74
  if data.get("success") and data.get("link"):
75
  direct_link = data["link"]
76
  slug_cache[slug] = direct_link
77
  return direct_link
 
 
 
 
 
 
78
  except Exception as e:
79
+ print(f"解锁API错误: {e}")
80
  return None
81
 
82
  async def send_modified_message(client, dest_entity, original_msg):
83
  if isinstance(original_msg, MessageService):
 
84
  return
85
 
86
  if not original_msg.text:
87
  await client.forward_messages(dest_entity, original_msg)
 
88
  return
89
 
90
+ slug = get_slug_from_message(original_msg)
91
  if not slug:
92
  await client.forward_messages(dest_entity, original_msg)
 
93
  return
94
 
95
  direct_link = get_direct_link(slug)
96
  if not direct_link:
97
  await client.forward_messages(dest_entity, original_msg)
 
98
  return
99
 
100
+ # 直接替换文本中的所有链接为直链
101
+ new_text = original_msg.text
102
+ if original_msg.entities:
103
+ # 从后往前替换,避免偏移问题
104
+ for entity in reversed(original_msg.entities):
105
+ url = None
106
+ if hasattr(entity, 'url'):
107
+ url = entity.url
108
+ if url and extract_slug_from_url(url) == slug:
109
+ start = entity.offset
110
+ end = start + entity.length
111
+ new_text = new_text[:start] + direct_link + new_text[end:]
 
 
 
 
 
 
 
 
112
 
113
  await client.send_message(dest_entity, new_text)
 
114
 
115
+ async def forward_history(client, source_entity, dest_entity, limit):
116
+ print(f"处理历史消息: {source_entity.id}")
117
+ messages = []
118
+ async for msg in client.iter_messages(source_entity, limit=limit, reverse=True):
119
+ messages.append(msg)
120
+ if not messages:
121
+ return None
122
+ for msg in messages:
123
+ await send_modified_message(client, dest_entity, msg)
124
+ await asyncio.sleep(0.3)
125
+ return messages[-1].id
126
+
127
+ async def forward_new_messages(client, source_entity, dest_entity, last_id):
128
+ try:
129
+ async for msg in client.iter_messages(source_entity, limit=1):
130
+ latest = msg
131
+ break
132
+ else:
133
+ return last_id
134
+ if latest.id > last_id:
135
+ new_msgs = []
136
+ async for msg in client.iter_messages(source_entity, min_id=last_id, max_id=latest.id, reverse=True):
137
+ new_msgs.append(msg)
138
+ for msg in new_msgs:
139
+ await send_modified_message(client, dest_entity, msg)
140
+ await asyncio.sleep(0.3)
141
+ return latest.id
142
+ return last_id
143
+ except Exception as e:
144
+ print(f"轮询错误: {e}")
145
+ return last_id
146
+
147
+ async def main():
148
+ print("等待60秒...")
149
+ await asyncio.sleep(60)
150
+
151
+ client = TelegramClient(StringSession(SESSION_STRING), API_ID, API_HASH)
152
+ await client.start()
153
+ print("连接成功")
154
+
155
+ sources = []
156
+ for src in SOURCES:
157
+ try:
158
+ entity = await client.get_entity(src)
159
+ sources.append(entity)
160
+ print(f"加载源: {src}")
161
+ except Exception as e:
162
+ print(f"加载失败 {src}: {e}")
163
+
164
+ if not sources:
165
+ print("无可用源")
166
+ return
167
+
168
+ dest = await client.get_entity(DESTINATION)
169
+ print(f"目标: {DESTINATION}")
170
+
171
+ last_ids = await load_last_ids()
172
+
173
+ if HISTORY_LIMIT > 0:
174
+ print(f"转发历史 ({HISTORY_LIMIT}条/源)...")
175
+ for entity in sources:
176
+ key = str(entity.id)
177
+ new_id = await forward_history(client, entity, dest, HISTORY_LIMIT)
178
+ if new_id:
179
+ last_ids[key] = new_id
180
+ await save_last_ids(last_ids)
181
+ print("历史转发完成")
182
+
183
+ for entity in sources:
184
+ try:
185
+ @client.on(events.NewMessage(chats=entity))
186
+ async def handler(event):
187
+ await send_modified_message(client, dest, event.message)
188
+ print(f"实时监听: {entity.id}")
189
+ except Exception as e:
190
+ print(f"无法监听 {entity.id}: {e}")
191
+ polling_sources.append(entity)
192
+
193
+ for entity in polling_sources:
194
+ key = str(entity.id)
195
+ if key not in last_ids:
196
+ async for msg in client.iter_messages(entity, limit=1):
197
+ last_ids[key] = msg.id if msg else 0
198
+ break
199
+ else:
200
+ last_ids[key] = 0
201
+ await save_last_ids(last_ids)
202
+
203
+ async def poll():
204
+ while True:
205
+ for entity in polling_sources:
206
+ key = str(entity.id)
207
+ last = last_ids.get(key, 0)
208
+ new_last = await forward_new_messages(client, entity, dest, last)
209
+ if new_last != last:
210
+ last_ids[key] = new_last
211
+ await save_last_ids(last_ids)
212
+ await asyncio.sleep(POLL_INTERVAL)
213
+
214
+ if polling_sources:
215
+ asyncio.create_task(poll())
216
+ print(f"轮询启动, 间隔{POLL_INTERVAL}秒")
217
+
218
+ print("监听运行中...")
219
+ await client.run_until_disconnected()
220
+
221
+ if __name__ == "__main__":
222
+ try:
223
+ asyncio.run(main())
224
+ except KeyboardInterrupt:
225
+ print("停止")
226
+ except Exception as e:
227
+ print(f"错误: {e}")