SHA256
Отключить репосты и добавить Solana-модуль
This commit is contained in:
@@ -8,6 +8,7 @@ import json
|
||||
import mimetypes
|
||||
import os
|
||||
import random
|
||||
import re
|
||||
import string
|
||||
import subprocess
|
||||
import tempfile
|
||||
@@ -350,6 +351,56 @@ class ShinePyBotService:
|
||||
history_path = self._current_history_file()
|
||||
self._append_history(history_path, "system_event", {"event": event_type, **payload})
|
||||
|
||||
def _resolve_chat_id(self, chat_id: int) -> int:
|
||||
migrations = self.state.get("chat_id_migrations")
|
||||
if not isinstance(migrations, dict):
|
||||
return chat_id
|
||||
current = chat_id
|
||||
visited: set[int] = set()
|
||||
while current not in visited:
|
||||
visited.add(current)
|
||||
next_chat_id = migrations.get(str(current))
|
||||
if not isinstance(next_chat_id, int):
|
||||
break
|
||||
current = next_chat_id
|
||||
return current
|
||||
|
||||
def _remember_chat_migration(self, old_chat_id: int, new_chat_id: int, source: str) -> None:
|
||||
if old_chat_id == new_chat_id:
|
||||
return
|
||||
migrations = self.state.get("chat_id_migrations")
|
||||
if not isinstance(migrations, dict):
|
||||
migrations = {}
|
||||
self.state["chat_id_migrations"] = migrations
|
||||
if migrations.get(str(old_chat_id)) == new_chat_id:
|
||||
return
|
||||
migrations[str(old_chat_id)] = new_chat_id
|
||||
self._persist_state()
|
||||
with self.queue_lock:
|
||||
changed = False
|
||||
for job in self.queue:
|
||||
if job.get("chat_id") == old_chat_id:
|
||||
job["chat_id"] = new_chat_id
|
||||
job["updated_at"] = now_iso()
|
||||
changed = True
|
||||
if changed:
|
||||
self._persist_queue()
|
||||
self._append_history_event("chat_migrated_to_supergroup", {
|
||||
"oldChatId": old_chat_id,
|
||||
"newChatId": new_chat_id,
|
||||
"source": source,
|
||||
})
|
||||
|
||||
@staticmethod
|
||||
def _extract_migrate_to_chat_id(error_text: str) -> int | None:
|
||||
match = re.search(r'"migrate_to_chat_id"\s*:\s*(-?\d+)', error_text)
|
||||
if match:
|
||||
return int(match.group(1))
|
||||
match = re.search(r"'migrate_to_chat_id'\s*:\s*(-?\d+)", error_text)
|
||||
if match:
|
||||
return int(match.group(1))
|
||||
return None
|
||||
|
||||
def _handle_update(self, update: dict[str, Any]) -> None:
|
||||
message = update.get("message")
|
||||
update_type = "message"
|
||||
@@ -371,11 +422,17 @@ class ShinePyBotService:
|
||||
if not isinstance(chat_id, int) or not isinstance(message_id, int):
|
||||
return
|
||||
|
||||
migrate_to_chat_id = message.get("migrate_to_chat_id")
|
||||
if isinstance(migrate_to_chat_id, int):
|
||||
self._remember_chat_migration(chat_id, migrate_to_chat_id, "telegram_message")
|
||||
return
|
||||
|
||||
update_key = f"{chat_id}:{message_id}"
|
||||
if self._mark_processed_update(update_key):
|
||||
return
|
||||
|
||||
is_channel_post = update_type == "channel_post" or chat_type == "channel"
|
||||
is_group_message = update_type == "message" and chat_type in ("group", "supergroup")
|
||||
is_allowed_channel = (
|
||||
not is_channel_post
|
||||
or not self.cfg.allowed_channel_username
|
||||
@@ -387,10 +444,12 @@ class ShinePyBotService:
|
||||
text = (message.get("text") or message.get("caption") or "").strip()
|
||||
history_path = self._current_history_file()
|
||||
if author_username != self.cfg.allowed_username:
|
||||
if is_channel_post:
|
||||
self._append_history(history_path, "channel_context_message", {
|
||||
if is_channel_post or is_group_message:
|
||||
self._append_history(history_path, "chat_context_message", {
|
||||
"chatId": chat_id,
|
||||
"messageId": message_id,
|
||||
"updateType": update_type,
|
||||
"chatType": chat_type,
|
||||
"chatUsername": chat_username,
|
||||
"chatTitle": chat_title,
|
||||
"username": username,
|
||||
@@ -399,6 +458,8 @@ class ShinePyBotService:
|
||||
"hasVoice": bool(message.get("voice")),
|
||||
"hasAudio": bool(message.get("audio")),
|
||||
})
|
||||
if is_group_message:
|
||||
self._safe_send(chat_id, "Получил сообщение.", reply_to=message_id)
|
||||
return
|
||||
|
||||
if not text:
|
||||
@@ -412,6 +473,7 @@ class ShinePyBotService:
|
||||
chat_username=chat_username,
|
||||
chat_title=chat_title,
|
||||
author_signature=author_signature,
|
||||
chat_type=chat_type,
|
||||
)
|
||||
return
|
||||
if message.get("audio"):
|
||||
@@ -424,6 +486,7 @@ class ShinePyBotService:
|
||||
chat_username=chat_username,
|
||||
chat_title=chat_title,
|
||||
author_signature=author_signature,
|
||||
chat_type=chat_type,
|
||||
)
|
||||
return
|
||||
self._safe_send(chat_id, "Поддерживаются текст, voice и audio.", reply_to=message_id)
|
||||
@@ -437,6 +500,7 @@ class ShinePyBotService:
|
||||
"chatId": chat_id,
|
||||
"messageId": message_id,
|
||||
"updateType": update_type,
|
||||
"chatType": chat_type,
|
||||
"chatUsername": chat_username,
|
||||
"chatTitle": chat_title,
|
||||
"username": author_username,
|
||||
@@ -447,6 +511,7 @@ class ShinePyBotService:
|
||||
job["type"] = "text"
|
||||
job["text"] = text
|
||||
job["update_type"] = update_type
|
||||
job["chat_type"] = chat_type
|
||||
job["chat_username"] = chat_username
|
||||
job["chat_title"] = chat_title
|
||||
job["author_signature"] = author_signature
|
||||
@@ -466,6 +531,7 @@ class ShinePyBotService:
|
||||
chat_username: str = "",
|
||||
chat_title: str = "",
|
||||
author_signature: str = "",
|
||||
chat_type: str = "",
|
||||
) -> None:
|
||||
if not file_id:
|
||||
self._safe_send(chat_id, "Не удалось прочитать file_id голосового.", reply_to=message_id)
|
||||
@@ -475,6 +541,7 @@ class ShinePyBotService:
|
||||
"chatId": chat_id,
|
||||
"messageId": message_id,
|
||||
"updateType": update_type,
|
||||
"chatType": chat_type,
|
||||
"chatUsername": chat_username,
|
||||
"chatTitle": chat_title,
|
||||
"username": username,
|
||||
@@ -485,6 +552,7 @@ class ShinePyBotService:
|
||||
job["type"] = "voice"
|
||||
job["telegram_file_id"] = file_id
|
||||
job["update_type"] = update_type
|
||||
job["chat_type"] = chat_type
|
||||
job["chat_username"] = chat_username
|
||||
job["chat_title"] = chat_title
|
||||
job["author_signature"] = author_signature
|
||||
@@ -507,6 +575,7 @@ class ShinePyBotService:
|
||||
"message_id": message_id,
|
||||
"username": username,
|
||||
"update_type": "message",
|
||||
"chat_type": "",
|
||||
"chat_username": "",
|
||||
"chat_title": "",
|
||||
"author_signature": "",
|
||||
@@ -717,6 +786,7 @@ class ShinePyBotService:
|
||||
"Пришло сообщение в Telegram.\n"
|
||||
f"Тип: {job.get('type')}\n"
|
||||
f"Источник Telegram: {job.get('update_type', 'message')}\n"
|
||||
f"Тип чата: {job.get('chat_type') or ''}\n"
|
||||
f"Канал/чат: @{job.get('chat_username') or ''} {job.get('chat_title') or ''}\n"
|
||||
f"Username отправителя: @{job.get('username')}\n"
|
||||
f"Подпись автора в Telegram: {job.get('author_signature') or ''}\n"
|
||||
@@ -892,9 +962,20 @@ class ShinePyBotService:
|
||||
return
|
||||
if len(text) > 3900:
|
||||
text = text[:3900] + "\n...[обрезано]"
|
||||
resolved_chat_id = self._resolve_chat_id(chat_id)
|
||||
resolved_reply_to = reply_to if resolved_chat_id == chat_id else None
|
||||
try:
|
||||
self.telegram.send_message(chat_id, text, reply_to_message_id=reply_to)
|
||||
self.telegram.send_message(resolved_chat_id, text, reply_to_message_id=resolved_reply_to)
|
||||
except Exception as e:
|
||||
migrate_to_chat_id = self._extract_migrate_to_chat_id(str(e))
|
||||
if migrate_to_chat_id is not None:
|
||||
self._remember_chat_migration(resolved_chat_id, migrate_to_chat_id, "send_message_error")
|
||||
try:
|
||||
self.telegram.send_message(migrate_to_chat_id, text, reply_to_message_id=None)
|
||||
return
|
||||
except Exception as retry_error:
|
||||
print(f"[py-bot] sendMessage retry after migration error: {retry_error}", flush=True)
|
||||
return
|
||||
print(f"[py-bot] sendMessage error: {e}", flush=True)
|
||||
|
||||
def _schedule_self_restart(self) -> None:
|
||||
|
||||
Reference in New Issue
Block a user