11# -*- coding: utf-8 -*-
22import asyncio
3+ from pathlib import Path
34
45from aiogram import F
56from aiogram .fsm .context import FSMContext
@@ -57,22 +58,27 @@ async def admin_panel(message: Message, state: FSMContext):
5758 logger .exception (e )
5859
5960
61+ import os
62+ from pathlib import Path
63+
64+
6065@router .message (F .text == "Актуализация базы данных" )
6166async def update_db (message : Message ):
6267 """
6368 Актуализация базы данных:
6469 обновление ID и типа групп/каналов.
6570
6671 Последовательность действий:
72+ - Сканирует папку accounts/parsing для поиска доступных сессий;
6773 - Подключается к Telegram API для получения метаданных по username;
6874 - Определяет тип сущности (канал, супергруппа и т.д.);
6975 - Обновляет записи в базе через прямой UPDATE-запрос;
70- - Отправляет прогресс и статистику в чат администратора ;
71- - Обрабатывает FloodWaitError и другие исключения .
76+ - При FloodWaitError переключается на следующий аккаунт ;
77+ - Отправляет прогресс и статистику в чат администратора .
7278
7379 Особенности:
7480 - Доступ только для администраторов;
75- - Реализована защита от FloodWait;
81+ - Автоматическое переключение между аккаунтами при FloodWait;
7682 - Используется режим WAL для избежания блокировок БД.
7783
7884 :param message: (Message) Входящее сообщение от администратора.
@@ -82,25 +88,36 @@ async def update_db(message: Message):
8288 # 1. Выполняем миграцию (один раз за вызов)
8389 add_id_column ()
8490
85- # 2. Подключаемся к Telegram
86- client = TelegramClient ('accounts/parsing/998771571378' , api_id , api_hash )
87- await client .connect ()
91+ # 2. Сканируем папку на наличие session-файлов
92+ sessions_dir = Path ('accounts/parsing' )
93+ session_files = list (sessions_dir .glob ('*.session' ))
94+
95+ if not session_files :
96+ await message .answer ("❌ Не найдено ни одного session-файла в папке accounts/parsing" )
97+ logger .error ("Session-файлы не найдены" )
98+ return
8899
89- # 3. Небольшая пауза для стабильности
90- await asyncio .sleep (1 )
100+ # Получаем имена сессий (без расширения .session)
101+ available_sessions = [str (f .stem ) for f in session_files ]
102+ logger .info (f"Найдено { len (available_sessions )} аккаунтов: { available_sessions } " )
103+
104+ await message .answer (
105+ f"🔍 Найдено аккаунтов: { len (available_sessions )} \n "
106+ f"📱 Аккаунты: { ', ' .join ([s .split ('/' )[- 1 ] for s in available_sessions ])} "
107+ )
91108
92109 try :
93110 # 3. Убедимся, что БД подключена
94111 if db .is_closed ():
95112 db .connect ()
96113
97114 # 4. Получаем записи с username и group_type='group', которые ещё НЕ обновлены
98- groups_to_update = TelegramGroup .select ().where (
115+ groups_to_update = list ( TelegramGroup .select ().where (
99116 (TelegramGroup .username .is_null (False )) &
100117 (TelegramGroup .group_type == 'group' )
101- )
118+ ))
102119
103- total_count = groups_to_update . count ( )
120+ total_count = len ( groups_to_update )
104121 logger .info (f"Найдено { total_count } групп для обновления" )
105122
106123 # Отправляем начальное сообщение
@@ -109,78 +126,129 @@ async def update_db(message: Message):
109126 processed = 0
110127 updated = 0
111128 errors = 0
129+ current_session_index = 0
130+
131+ # 5. Основной цикл обработки групп
132+ while processed < total_count and current_session_index < len (available_sessions ):
133+ # Подключаемся к текущему аккаунту
134+ session_path = f'accounts/parsing/{ available_sessions [current_session_index ]} '
135+ client = TelegramClient (session_path , api_id , api_hash )
112136
113- for group in groups_to_update :
114137 try :
115- # 5. Получаем сущность Telegram по username
116- entity = await client .get_entity (group .username )
117-
118- # 6. Определяем тип сущности
119- if entity .megagroup :
120- new_group_type = 'Группа (супергруппа)'
121- elif entity .broadcast :
122- new_group_type = 'Канал'
123- else :
124- new_group_type = 'Обычный чат (группа старого типа)'
125-
126- # 7. Обновляем запись через UPDATE запрос
127- TelegramGroup .update (
128- id = entity .id ,
129- group_type = new_group_type
130- ).where (
131- TelegramGroup .group_hash == group .group_hash
132- ).execute ()
133-
134- processed += 1
135- updated += 1
136-
137- logger .info (
138- f"[{ processed } /{ total_count } ] Обновлено: { group .username } | ID: { entity .id } | Тип: { new_group_type } "
139- )
140-
141- # Каждые 10 обновлений отправляем прогресс
142- if processed % 10 == 0 :
143- await message .answer (
144- f"📊 Прогресс: { processed } /{ total_count } \n "
145- f"✅ Обновлено: { updated } \n "
146- f"❌ Ошибок: { errors } "
147- )
148-
149- # 8. Пауза для избежания бана от Telegram
150- await asyncio .sleep (5 )
151-
152- except FloodWaitError as e :
153- wait_time = e .seconds
154- processed += 1
155- errors += 1
156-
157- logger .warning (
158- f"FloodWait для { group .username } : нужно подождать { wait_time } секунд "
159- f"({ wait_time / 3600 :.1f} часов). Останавливаем обработку."
160- )
161-
162- # Отправляем итоговую статистику при FloodWait
163- await message .answer (
164- f"⚠️ Telegram ограничил запросы.\n \n "
165- f"📊 Обработано: { processed } /{ total_count } \n "
166- f"✅ Обновлено: { updated } \n "
167- f"❌ Ошибок: { errors } \n \n "
168- f"⏱ Необходимо подождать { wait_time / 3600 :.1f} часов ({ wait_time } сек)"
169- )
170- break # Останавливаем обработку
138+ await client .connect ()
139+ await asyncio .sleep (1 )
140+
141+ current_account = available_sessions [current_session_index ].split ('/' )[- 1 ]
142+ logger .info (f"Используется аккаунт: { current_account } " )
143+ await message .answer (f"📱 Используется аккаунт: { current_account } " )
144+
145+ # Обрабатываем группы с текущим аккаунтом
146+ for group in groups_to_update [processed :]:
147+ try :
148+ # Получаем сущность Telegram по username
149+ entity = await client .get_entity (group .username )
150+
151+ # Определяем тип сущности
152+ if entity .megagroup :
153+ new_group_type = 'Группа (супергруппа)'
154+ elif entity .broadcast :
155+ new_group_type = 'Канал'
156+ else :
157+ new_group_type = 'Обычный чат (группа старого типа)'
158+
159+ # Обновляем запись через UPDATE запрос
160+ TelegramGroup .update (
161+ id = entity .id ,
162+ group_type = new_group_type
163+ ).where (
164+ TelegramGroup .group_hash == group .group_hash
165+ ).execute ()
166+
167+ processed += 1
168+ updated += 1
169+
170+ logger .info (
171+ f"[{ processed } /{ total_count } ] Обновлено: { group .username } | "
172+ f"ID: { entity .id } | Тип: { new_group_type } "
173+ )
174+
175+ # Каждые 10 обновлений отправляем прогресс
176+ if processed % 10 == 0 :
177+ await message .answer (
178+ f"📊 Прогресс: { processed } /{ total_count } \n "
179+ f"✅ Обновлено: { updated } \n "
180+ f"❌ Ошибок: { errors } \n "
181+ f"📱 Аккаунт: { current_account } "
182+ )
183+
184+ # Пауза для избежания бана от Telegram
185+ await asyncio .sleep (5 )
186+
187+ except FloodWaitError as e :
188+ wait_time = e .seconds
189+ errors += 1
190+
191+ logger .warning (
192+ f"FloodWait для { group .username } (аккаунт { current_account } ): "
193+ f"нужно подождать { wait_time } секунд ({ wait_time / 3600 :.1f} часов)"
194+ )
195+
196+ # Отправляем уведомление о FloodWait
197+ await message .answer (
198+ f"⚠️ FloodWait на аккаунте { current_account } \n \n "
199+ f"📊 Обработано: { processed } /{ total_count } \n "
200+ f"✅ Обновлено: { updated } \n "
201+ f"❌ Ошибок: { errors } \n \n "
202+ f"⏱ Ожидание: { wait_time / 3600 :.1f} ч ({ wait_time } сек)"
203+ )
204+
205+ # Переключаемся на следующий аккаунт
206+ current_session_index += 1
207+
208+ if current_session_index < len (available_sessions ):
209+ await message .answer (
210+ f"🔄 Переключаюсь на аккаунт "
211+ f"{ available_sessions [current_session_index ].split ('/' )[- 1 ]} "
212+ )
213+ else :
214+ await message .answer (
215+ "❌ Все аккаунты исчерпаны. Актуализация остановлена."
216+ )
217+
218+ break # Выходим из цикла групп, переключаемся на новый аккаунт
219+
220+ except Exception as e :
221+ processed += 1
222+ errors += 1
223+ logger .error (
224+ f"[{ processed } /{ total_count } ] Ошибка при обработке "
225+ f"{ group .username } : { e } "
226+ )
171227
172228 except Exception as e :
173- processed += 1
174- errors += 1
175- logger . error ( f"[ { processed } / { total_count } ] Ошибка при обработке { group . username } : { e } " )
229+ logger . error ( f"Ошибка подключения к аккаунту { current_account } : { e } " )
230+ await message . answer ( f"❌ Ошибка аккаунта { current_account } : { e } " )
231+ current_session_index += 1
176232
177- # Финальная статистика (если не было FloodWait)
178- else :
233+ finally :
234+ await client .disconnect ()
235+
236+ # Финальная статистика
237+ if processed >= total_count :
179238 await message .answer (
180239 f"✅ Актуализация завершена!\n \n "
181240 f"📊 Всего обработано: { processed } /{ total_count } \n "
182241 f"✅ Успешно обновлено: { updated } \n "
183- f"❌ Ошибок: { errors } "
242+ f"❌ Ошибок: { errors } \n "
243+ f"📱 Использовано аккаунтов: { current_session_index + 1 } /{ len (available_sessions )} "
244+ )
245+ else :
246+ await message .answer (
247+ f"⚠️ Актуализация остановлена.\n \n "
248+ f"📊 Обработано: { processed } /{ total_count } \n "
249+ f"✅ Успешно обновлено: { updated } \n "
250+ f"❌ Ошибок: { errors } \n "
251+ f"📱 Все { len (available_sessions )} аккаунтов исчерпаны"
184252 )
185253
186254 except Exception as e :
@@ -191,7 +259,6 @@ async def update_db(message: Message):
191259 if not db .is_closed ():
192260 db .close ()
193261
194- await client .disconnect ()
195262 logger .info ("Актуализация завершена." )
196263
197264
0 commit comments