-
Notifications
You must be signed in to change notification settings - Fork 1
/
main.py
239 lines (203 loc) · 8.46 KB
/
main.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
# main.py
import asyncio
import logging
from telegram.ext import Application, CommandHandler
from telethon import TelegramClient, events
from database import Database
from channel_manager import ChannelManager
from config import Config
from message_handler import MyMessageHandler
from commands import BotCommands
from telegram import (
Update,
InlineKeyboardButton,
InlineKeyboardMarkup,
CallbackQuery
)
from telegram.ext import (
ContextTypes,
ConversationHandler,
CallbackQueryHandler,
MessageHandler,
CommandHandler,
filters
)
from locales import get_text
class ForwardBot:
def __init__(self, config):
self.config = config
self.db = Database(config.DATABASE_NAME)
# Initialize Telegram bot
self.application = Application.builder().token(config.TELEGRAM_TOKEN).build()
# Initialize Telethon client
self.client = TelegramClient(
config.SESSION_NAME,
config.API_ID,
config.API_HASH
)
# Initialize components
self.channel_manager = ChannelManager(self.db, config, self.client)
self.message_handler = MyMessageHandler(self.db, self.client, self.application.bot)
# Setup handlers
self.setup_handlers()
def setup_handlers(self):
"""设置消息处理器"""
# 命令处理器
self.application.add_handler(CommandHandler("start", self.start_command))
self.application.add_handler(CommandHandler("channels", self.channels_command))
self.application.add_handler(CommandHandler("language", self.language_command))
self.application.add_handler(CommandHandler("help", self.help_command))
# 添加频道管理处理器
for handler in self.channel_manager.get_handlers():
self.application.add_handler(handler)
# 添加错误处理器
self.application.add_error_handler(self.error_handler)
async def error_handler(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
"""处理错误"""
logging.error(f"Update {update} caused error {context.error}")
try:
if update and update.effective_chat:
lang = self.db.get_user_language(update.effective_chat.id)
if update.callback_query:
await update.callback_query.message.reply_text(
get_text(lang, 'error_occurred')
)
elif update.message:
await update.message.reply_text(
get_text(lang, 'error_occurred')
)
except Exception as e:
logging.error(f"Error in error handler: {e}")
async def start_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
"""处理 /start 命令"""
if update.effective_user.id != self.config.OWNER_ID:
lang = self.db.get_user_language(update.effective_user.id)
await update.message.reply_text(get_text(lang, 'unauthorized'))
return
lang = self.db.get_user_language(update.effective_user.id)
await update.message.reply_text(get_text(lang, 'welcome'))
async def help_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
"""处理 /help 命令"""
if update.effective_user.id != self.config.OWNER_ID:
lang = self.db.get_user_language(update.effective_user.id)
await update.message.reply_text(get_text(lang, 'unauthorized'))
return
lang = self.db.get_user_language(update.effective_user.id)
help_text = get_text(lang, 'help_message')
try:
await update.message.reply_text(
help_text,
parse_mode='Markdown',
reply_markup=InlineKeyboardMarkup([[
InlineKeyboardButton(
get_text(lang, 'channel_management'),
callback_data="channel_management"
)
]])
)
except Exception as e:
logging.error(f"Error sending help message: {e}")
# 如果Markdown解析失败,尝试发送纯文本
try:
await update.message.reply_text(
help_text,
parse_mode=None,
reply_markup=InlineKeyboardMarkup([[
InlineKeyboardButton(
get_text(lang, 'channel_management'),
callback_data="channel_management"
)
]])
)
except Exception as e2:
logging.error(f"Error sending plain text help message: {e2}")
await update.message.reply_text(
get_text(lang, 'error_occurred')
)
async def language_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
"""处理 /language 命令"""
if update.effective_user.id != self.config.OWNER_ID:
lang = self.db.get_user_language(update.effective_user.id)
await update.message.reply_text(get_text(lang, 'unauthorized'))
return
await self.channel_manager.show_language_settings(update, context)
async def channels_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
"""处理 /channels 命令"""
if update.effective_user.id != self.config.OWNER_ID:
lang = self.db.get_user_language(update.effective_user.id)
await update.message.reply_text(get_text(lang, 'unauthorized'))
return
await self.channel_manager.show_channel_management(update, context)
async def initialize(self):
"""初始化机器人配置"""
try:
# 设置命令列表
await BotCommands.setup_commands(self.application)
logging.info("Successfully initialized bot commands")
except Exception as e:
logging.error(f"Failed to initialize bot: {e}")
raise
async def start(self):
"""启动机器人"""
try:
# 初始化配置
await self.initialize()
# 启动 Telethon 客户端
await self.client.start(phone=self.config.PHONE_NUMBER)
# 启动清理任务
await self.message_handler.start_cleanup_task()
# 注册消息处理器
@self.client.on(events.NewMessage)
async def handle_new_message(event):
await self.message_handler.handle_channel_message(event)
# 启动机器人
await self.application.initialize()
await self.application.start()
await self.application.updater.start_polling()
print("Bot started successfully!")
# 保持运行
await self.client.run_until_disconnected()
except Exception as e:
logging.error(f"Error starting bot: {e}")
raise
finally:
# 清理资源
await self.stop()
async def stop(self):
"""停止机器人"""
try:
if self.message_handler.cleanup_task:
self.message_handler.cleanup_task.cancel()
# 清理所有剩余的临时文件
for file_path in list(self.message_handler.temp_files.keys()):
await self.message_handler.cleanup_file(file_path)
await self.application.stop()
await self.client.disconnect()
self.db.cleanup()
print("Bot stopped successfully!")
except Exception as e:
logging.error(f"Error stopping bot: {e}")
async def main():
"""主函数"""
# 设置日志
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.StreamHandler(),
logging.FileHandler('bot.log')
]
)
try:
# 初始化配置
config = Config()
# 创建并启动机器人
bot = ForwardBot(config)
await bot.start()
except Exception as e:
logging.error(f"Critical error: {e}")
import traceback
logging.error(f"Traceback:\n{traceback.format_exc()}")
raise
if __name__ == "__main__":
asyncio.run(main())