refactor requirements and rss_generator: replace direct get_chat calls with cached_get_chat for improved performance and update requirements.txt to uncomment Kurigram

This commit is contained in:
vvzvlad
2025-06-10 02:40:23 +03:00
parent 0999e86f2b
commit b7a8f4f60d
3 changed files with 134 additions and 6 deletions
+2 -2
View File
@@ -1,8 +1,8 @@
fastapi==0.115.8
uvicorn==0.34.0
python-multipart==0.0.20
#Kurigram
git+https://github.com/KurimuzonAkuma/pyrogram.git@dev#egg=Kurigram
Kurigram
#git+https://github.com/KurimuzonAkuma/pyrogram.git@dev#egg=Kurigram
TgCrypto
uvloop
pillow==11.1.0
+8 -4
View File
@@ -333,10 +333,12 @@ async def generate_channel_rss(channel: str | int,
channel_info_start_time = time.time()
try:
from tg_cache import cached_get_chat
channel = post_parser.channel_name_prepare(channel)
channel_info = await post_parser.client.get_chat(channel)
channel_info = await cached_get_chat(post_parser.client, channel)
channel_title = channel_info.title or f"Telegram: {channel}"
channel_username = post_parser.get_channel_username(channel_info)
channel_username = channel_info.username or (str(channel_info.id) if channel_info.id and str(channel_info.id).startswith('-100') else None)
if not channel_username:
# Use prepared channel (which could be int) for error feed if username fails
logger.warning(f"Could not get username for channel {channel}, using identifier for error feed.")
@@ -468,10 +470,12 @@ async def generate_channel_html(channel: str | int,
channel_info_start_time = time.time()
try:
from tg_cache import cached_get_chat
channel = post_parser.channel_name_prepare(channel)
logger.debug(f"Prepared channel identifier for HTML: {channel} (type: {type(channel)})") # Log prepared channel
channel_info = await post_parser.client.get_chat(channel)
channel_username = post_parser.get_channel_username(channel_info)
channel_info = await cached_get_chat(post_parser.client, channel)
channel_username = channel_info.username or (str(channel_info.id) if channel_info.id and str(channel_info.id).startswith('-100') else None)
if not channel_username:
logger.warning(f"Could not get username for channel {channel} in HTML generation, returning error feed structure (as string). NOTE: This should ideally return HTML error page.")
# For HTML, returning an error feed string might not be ideal. Consider returning a dedicated HTML error page.
+124
View File
@@ -0,0 +1,124 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
import json
import pickle
import logging
import time
from datetime import datetime, timedelta
from typing import Any, Optional, Union
from pyrogram import Client
from pyrogram.types import Chat, Message
logger = logging.getLogger(__name__)
# Путь к директории кеша
CACHE_DIR = os.path.join('data', 'tgcache')
def _get_cache_file_path(channel_id: Union[str, int]) -> str:
"""Возвращает путь к файлу кеша для канала"""
if not os.path.exists(CACHE_DIR):
os.makedirs(CACHE_DIR, exist_ok=True)
logger.debug(f"cache_dir_created: path {CACHE_DIR}")
# Преобразуем в строку для унификации
channel_id_str = str(channel_id)
# Заменяем потенциально проблемные символы
safe_filename = channel_id_str.replace('/', '_').replace('\\', '_')
return os.path.join(CACHE_DIR, f"{safe_filename}.cache")
def _save_to_cache(channel_id: Union[str, int], chat_data: Chat) -> None:
"""Сохраняет данные чата в кеш"""
try:
cache_file = _get_cache_file_path(channel_id)
# Создаем метаданные кеша
cache_data = {
'timestamp': time.time(),
'chat_data': pickle.dumps(chat_data)
}
with open(cache_file, 'wb') as f:
pickle.dump(cache_data, f)
logger.debug(f"chat_cache_saved: channel {channel_id}, file {cache_file}")
except Exception as e:
logger.error(f"cache_save_error: channel {channel_id}, error {str(e)}")
def _get_from_cache(channel_id: Union[str, int], max_age_seconds: int = 86400) -> Optional[Chat]:
"""
Получает данные чата из кеша если они не старше указанного возраста
Args:
channel_id: ID или username канала
max_age_seconds: Максимальный возраст кеша в секундах (по умолчанию 1 день)
Returns:
Chat объект или None если кеш не найден или устарел
"""
try:
cache_file = _get_cache_file_path(channel_id)
if not os.path.exists(cache_file):
logger.debug(f"chat_cache_miss: channel {channel_id}, cache file not found")
return None
with open(cache_file, 'rb') as f:
cache_data = pickle.load(f)
# Проверяем возраст кеша
cache_age = time.time() - cache_data['timestamp']
if cache_age > max_age_seconds:
logger.debug(f"chat_cache_expired: channel {channel_id}, age {cache_age:.1f}s > max {max_age_seconds}s")
return None
# Восстанавливаем объект Chat из пикла
chat_data = pickle.loads(cache_data['chat_data'])
logger.debug(f"chat_cache_hit: channel {channel_id}, age {cache_age:.1f}s")
return chat_data
except Exception as e:
logger.error(f"cache_read_error: channel {channel_id}, error {str(e)}")
# В случае ошибки чтения кеша лучше вернуть None и запросить свежие данные
return None
def adapt_chat_for_get_username(chat: Chat) -> Chat:
"""
Адаптирует объект Chat для использования в методе get_channel_username
Метод get_channel_username ожидает объект Message, но использует только его атрибут chat,
поэтому мы можем передать сам объект Chat без обертки
"""
return chat
async def cached_get_chat(client: Client, channel_id: Union[str, int], cache_ttl: int = 86400) -> Chat:
"""
Получает информацию о чате с кешированием.
Args:
client: Pyrogram клиент
channel_id: ID или username канала
cache_ttl: Время жизни кеша в секундах (по умолчанию 1 день)
Returns:
Chat объект, как и оригинальный client.get_chat()
"""
# Пробуем получить из кеша
cached_chat = _get_from_cache(channel_id, cache_ttl)
if cached_chat is not None:
return cached_chat
# Если в кеше нет или кеш устарел, запрашиваем через API
try:
logger.debug(f"chat_cache_request: fetching fresh data for channel {channel_id}")
chat_data = await client.get_chat(channel_id)
# Сохраняем в кеш
_save_to_cache(channel_id, chat_data)
return chat_data
except Exception as e:
logger.error(f"chat_request_error: channel {channel_id}, error {str(e)}")
# Пробрасываем ошибку дальше, как и оригинальный метод
raise