UNSTABLE | ok

This commit is contained in:
wheelchairy 2025-03-27 11:30:35 +03:00
parent 4992e71948
commit 74efe83f07
4 changed files with 134 additions and 66 deletions

View File

@ -37,6 +37,14 @@ cp .env.example .env
## Запуск ## Запуск
1. Активируйте виртуальное окружение:
```bash
source venv/bin/activate # Linux/macOS
# или
venv\Scripts\activate # Windows
```
2. Запустите приложение:
```bash ```bash
python main_urwid.py python main_urwid.py
``` ```

View File

@ -1,4 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*-
""" """
Telegram TUI Client Telegram TUI Client
Консольный клиент Telegram на базе urwid Консольный клиент Telegram на базе urwid

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
""" """
Telegram TUI Client Telegram TUI Client
Консольный клиент Telegram на базе urwid Консольный клиент Telegram на базе urwid

View File

@ -1,4 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*-
""" """
Telegram TUI Client Telegram TUI Client
Консольный клиент Telegram на базе urwid Консольный клиент Telegram на базе urwid
@ -100,16 +101,14 @@ class ChatWidget(urwid.WidgetWrap):
('fixed', 3, avatar), ('fixed', 3, avatar),
content content
]), ]),
'chat' if not self.is_selected else 'chat_selected' None
) )
def selectable(self): def selectable(self):
return True return True
def keypress(self, size, key): def keypress(self, size, key):
if key in ('up', 'down'): return key
return key
return super().keypress(size, key)
class MessageWidget(urwid.WidgetWrap): class MessageWidget(urwid.WidgetWrap):
"""Виджет сообщения""" """Виджет сообщения"""
@ -182,8 +181,10 @@ class TelegramTUI:
# Создаем виджеты чатов # Создаем виджеты чатов
self.search_edit = urwid.Edit(('header', "Поиск: ")) self.search_edit = urwid.Edit(('header', "Поиск: "))
self.chat_list = urwid.ListBox(urwid.SimpleFocusListWalker([])) self.chat_walker = urwid.SimpleFocusListWalker([])
self.message_list = urwid.ListBox(urwid.SimpleFocusListWalker([])) self.chat_list = urwid.ListBox(self.chat_walker)
self.message_walker = urwid.SimpleFocusListWalker([])
self.message_list = urwid.ListBox(self.message_walker)
self.input_edit = urwid.Edit(('header', "Сообщение: ")) self.input_edit = urwid.Edit(('header', "Сообщение: "))
# Создаем экраны # Создаем экраны
@ -201,15 +202,19 @@ class TelegramTUI:
) )
self.chat_widget = urwid.Columns([ self.chat_widget = urwid.Columns([
('weight', 30, urwid.Pile([ ('weight', 30, urwid.LineBox(
('pack', urwid.Text(('help', "Tab - переключение фокуса, ↑↓ - выбор чата, Enter - открыть чат, Esc - назад, / - поиск, [] - папки"), align='center')), urwid.Pile([
('pack', self.search_edit), ('pack', urwid.Text(('help', "Tab - переключение фокуса, ↑↓ - выбор чата, Enter - открыть чат, Esc - назад, / - поиск, [] - папки"), align='center')),
self.chat_list ('pack', self.search_edit),
])), self.chat_list
('weight', 70, urwid.Pile([ ])
self.message_list, )),
('pack', self.input_edit) ('weight', 70, urwid.LineBox(
])) urwid.Pile([
self.message_list,
('pack', self.input_edit)
])
))
]) ])
# Создаем основной виджет # Создаем основной виджет
@ -280,13 +285,22 @@ class TelegramTUI:
try: try:
# Получаем папки # Получаем папки
if not self.folders: if not self.folders:
self.folders = await self.telegram_client.get_dialogs_folders() try:
# Проверяем наличие архива
self.folders = [1] if await self.telegram_client.get_dialogs(limit=1, folder=1) else []
except Exception as e:
print(f"Ошибка получения папок: {e}")
self.folders = []
# Получаем диалоги # Получаем диалоги
dialogs = await self.telegram_client.get_dialogs( try:
limit=100, dialogs = await self.telegram_client.get_dialogs(
folder=self.current_folder limit=100,
) folder=self.current_folder
)
except Exception as e:
print(f"Ошибка получения диалогов: {e}")
dialogs = []
# Фильтруем по поисковому запросу # Фильтруем по поисковому запросу
search_query = normalize_text(self.search_edit.get_edit_text().lower()) search_query = normalize_text(self.search_edit.get_edit_text().lower())
@ -297,21 +311,45 @@ class TelegramTUI:
] ]
# Очищаем список # Очищаем список
self.chat_list.body.clear() self.chat_walker[:] = []
# Добавляем чаты # Добавляем чаты
for i, dialog in enumerate(dialogs): for i, dialog in enumerate(dialogs):
chat = ChatWidget( try:
chat_id=dialog.id, # Получаем имя и сообщение
name=str(dialog.name), entity = dialog.entity
message=str(dialog.message.message if dialog.message else ""),
is_selected=(i == self.selected_chat_index), # Определяем имя чата
folder=1 if self.current_folder else 0 if hasattr(entity, 'title') and entity.title:
) name = entity.title
self.chat_list.body.append(chat) elif hasattr(entity, 'first_name'):
name = entity.first_name
if hasattr(entity, 'last_name') and entity.last_name:
name += f" {entity.last_name}"
else:
name = "Без названия"
# Получаем последнее сообщение
if dialog.message:
message = dialog.message.message if hasattr(dialog.message, 'message') else ""
else:
message = ""
chat = ChatWidget(
chat_id=dialog.id,
name=name,
message=message,
is_selected=(i == self.selected_chat_index),
folder=1 if self.current_folder else 0
)
self.chat_walker.append(chat)
except Exception as e:
print(f"Ошибка создания виджета чата: {e}")
print(f"Тип объекта: {type(dialog.entity)}")
print(f"Атрибуты: {dir(dialog.entity)}")
# Обновляем фокус # Обновляем фокус
if self.chat_list.body: if self.chat_walker:
self.chat_list.set_focus(self.selected_chat_index) self.chat_list.set_focus(self.selected_chat_index)
self.update_selected_chat() self.update_selected_chat()
@ -320,9 +358,12 @@ class TelegramTUI:
def update_selected_chat(self): def update_selected_chat(self):
"""Обновляет выделение выбранного чата""" """Обновляет выделение выбранного чата"""
for i, chat in enumerate(self.chat_list.body): try:
chat.is_selected = (i == self.selected_chat_index) for i, chat in enumerate(self.chat_walker):
chat.update_widget() chat.is_selected = (i == self.selected_chat_index)
chat.update_widget()
except Exception as e:
print(f"Ошибка обновления выделения: {e}")
async def update_message_list(self, chat_id): async def update_message_list(self, chat_id):
"""Обновляет список сообщений""" """Обновляет список сообщений"""
@ -337,25 +378,47 @@ class TelegramTUI:
me = await self.telegram_client.get_me() me = await self.telegram_client.get_me()
# Очищаем список # Очищаем список
self.message_list.body.clear() self.message_walker[:] = []
# Добавляем сообщения # Добавляем сообщения
for msg in reversed(messages): for msg in reversed(messages):
try: try:
is_me = msg.from_id.user_id == me.id # Определяем, отправлено ли сообщение нами
except:
is_me = False is_me = False
if hasattr(msg, 'from_id') and msg.from_id:
message = MessageWidget( if hasattr(msg.from_id, 'user_id'):
text=str(msg.message), is_me = msg.from_id.user_id == me.id
username=str(msg.sender.first_name if msg.sender else "Неизвестный"),
is_me=is_me, # Получаем текст сообщения
send_time=msg.date.strftime("%H:%M") text = msg.message if hasattr(msg, 'message') else "Медиа"
)
self.message_list.body.append(message) # Получаем имя отправителя
username = ""
if hasattr(msg, 'sender') and msg.sender:
if hasattr(msg.sender, 'first_name'):
username = msg.sender.first_name
if hasattr(msg.sender, 'last_name') and msg.sender.last_name:
username += f" {msg.sender.last_name}"
elif hasattr(msg.sender, 'title'):
username = msg.sender.title
# Если не удалось получить имя, используем Me/Другой
if not username:
username = "Я" if is_me else "Неизвестный"
message = MessageWidget(
text=text,
username=username,
is_me=is_me,
send_time=msg.date.strftime("%H:%M")
)
self.message_walker.append(message)
except Exception as e:
print(f"Ошибка создания виджета сообщения: {e}")
# Прокручиваем к последнему сообщению # Прокручиваем к последнему сообщению
self.message_list.set_focus(len(self.message_list.body) - 1) if self.message_walker:
self.message_list.set_focus(len(self.message_walker) - 1)
except Exception as e: except Exception as e:
print(f"Ошибка обновления сообщений: {e}") print(f"Ошибка обновления сообщений: {e}")
@ -366,18 +429,21 @@ class TelegramTUI:
# Переключаем фокус # Переключаем фокус
if self.focused_element == "chat_list": if self.focused_element == "chat_list":
self.focused_element = "search" self.focused_element = "search"
self.chat_widget.set_focus_column(0) self.chat_widget.focus_position = 0
self.chat_widget.contents[0][0].set_focus(1) # Фокус на поиск pile = self.chat_widget.widget_list[0].original_widget # Получаем Pile из LineBox
pile.focus_position = 1 # Фокус на поиск
else: else:
self.focused_element = "chat_list" self.focused_element = "chat_list"
self.chat_widget.set_focus_column(0) self.chat_widget.focus_position = 0
self.chat_widget.contents[0][0].set_focus(2) # Фокус на список чатов pile = self.chat_widget.widget_list[0].original_widget # Получаем Pile из LineBox
pile.focus_position = 2 # Фокус на список чатов
elif key == '/': elif key == '/':
# Фокус на поиск # Фокус на поиск
self.focused_element = "search" self.focused_element = "search"
self.chat_widget.set_focus_column(0) self.chat_widget.focus_position = 0
self.chat_widget.contents[0][0].set_focus(1) pile = self.chat_widget.widget_list[0].original_widget # Получаем Pile из LineBox
pile.focus_position = 1
elif key == '[': elif key == '[':
# Переход в предыдущую папку # Переход в предыдущую папку
@ -395,28 +461,28 @@ class TelegramTUI:
elif key == 'up' and self.focused_element == "chat_list": elif key == 'up' and self.focused_element == "chat_list":
# Выбор предыдущего чата # Выбор предыдущего чата
if self.chat_list.body: if self.chat_walker:
self.selected_chat_index = max(0, self.selected_chat_index - 1) self.selected_chat_index = max(0, self.selected_chat_index - 1)
self.chat_list.set_focus(self.selected_chat_index) self.chat_list.set_focus(self.selected_chat_index)
self.update_selected_chat() self.update_selected_chat()
elif key == 'down' and self.focused_element == "chat_list": elif key == 'down' and self.focused_element == "chat_list":
# Выбор следующего чата # Выбор следующего чата
if self.chat_list.body: if self.chat_walker:
self.selected_chat_index = min(len(self.chat_list.body) - 1, self.selected_chat_index + 1) self.selected_chat_index = min(len(self.chat_walker) - 1, self.selected_chat_index + 1)
self.chat_list.set_focus(self.selected_chat_index) self.chat_list.set_focus(self.selected_chat_index)
self.update_selected_chat() self.update_selected_chat()
elif key == 'enter' and self.focused_element == "chat_list": elif key == 'enter' and self.focused_element == "chat_list":
# Открываем выбранный чат # Открываем выбранный чат
focused = self.chat_list.get_focus()[0] if self.chat_walker:
if focused: focused = self.chat_walker[self.selected_chat_index]
await self.update_message_list(focused.chat_id) await self.update_message_list(focused.chat_id)
self.chat_widget.set_focus_column(1) # Переключаемся на сообщения self.chat_widget.focus_position = 1 # Переключаемся на сообщения
elif key == 'esc': elif key == 'esc':
# Возвращаемся к списку чатов # Возвращаемся к списку чатов
self.chat_widget.set_focus_column(0) self.chat_widget.focus_position = 0
self.focused_element = "chat_list" self.focused_element = "chat_list"
def unhandled_input(self, key): def unhandled_input(self, key):
@ -481,14 +547,6 @@ async def main():
# Инициализируем клиент Telegram # Инициализируем клиент Telegram
session_file = "talc.session" session_file = "talc.session"
# Если сессия существует и заблокирована, удаляем её
if os.path.exists(session_file):
try:
os.remove(session_file)
print("Старая сессия удалена")
except Exception as e:
print(f"Ошибка удаления сессии: {e}")
# Создаем клиент # Создаем клиент
client = TelegramClient( client = TelegramClient(
session_file, session_file,