📄📷 fix: Отправка фото + документа отдельными сообщениями
- Telegram не поддерживает фото+документ в одном сообщении - Теперь отправляются 2 сообщения: документ + фото - Исправлен UI — фото не очищается при выборе документа - Исправлена сериализация chat_id (int → str) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
parent
54e8cea522
commit
27729ab512
4 changed files with 32 additions and 19 deletions
BIN
data/scheduled_post_Gemini_Generated_Image_lnhu05lnhu05lnhu.png
Normal file
BIN
data/scheduled_post_Gemini_Generated_Image_lnhu05lnhu05lnhu.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.4 MiB |
|
|
@ -358,8 +358,14 @@ class Scheduler:
|
||||||
# HTTP прокси
|
# HTTP прокси
|
||||||
connector = aiohttp.TCPConnector()
|
connector = aiohttp.TCPConnector()
|
||||||
|
|
||||||
|
# Отправляем пост в тему форума
|
||||||
|
message_id = None
|
||||||
|
|
||||||
|
# Telegram не поддерживает фото + документ в одном сообщении
|
||||||
|
# Поэтому отправляем их отдельными сообщениями
|
||||||
|
|
||||||
|
# 1. Сначала документ (если есть) — он главный
|
||||||
if post.document_file_id:
|
if post.document_file_id:
|
||||||
# С документом - отправляем по file_id
|
|
||||||
url = f"{base_url}/sendDocument"
|
url = f"{base_url}/sendDocument"
|
||||||
params = {
|
params = {
|
||||||
'chat_id': ADMIN_CHAT_ID,
|
'chat_id': ADMIN_CHAT_ID,
|
||||||
|
|
@ -378,16 +384,16 @@ class Scheduler:
|
||||||
else:
|
else:
|
||||||
error_text = await resp.text()
|
error_text = await resp.text()
|
||||||
raise Exception(f"Telegram API {resp.status}: {error_text}")
|
raise Exception(f"Telegram API {resp.status}: {error_text}")
|
||||||
elif post.photo_file_id:
|
|
||||||
# С фото - отправляем по file_id
|
# 2. Потом фото (если есть) — отдельным сообщением
|
||||||
|
if post.photo_file_id:
|
||||||
url = f"{base_url}/sendPhoto"
|
url = f"{base_url}/sendPhoto"
|
||||||
params = {
|
params = {
|
||||||
'chat_id': ADMIN_CHAT_ID,
|
'chat_id': ADMIN_CHAT_ID,
|
||||||
'photo': post.photo_file_id,
|
'photo': post.photo_file_id,
|
||||||
'caption': post.text,
|
'caption': '📷 Приложение к посту' if post.document_file_id else post.text,
|
||||||
'parse_mode': 'HTML'
|
'parse_mode': 'HTML'
|
||||||
}
|
}
|
||||||
# Не добавляем message_thread_id для general (1) — это общий чат
|
|
||||||
if post.topic_id and post.topic_id > 1:
|
if post.topic_id and post.topic_id > 1:
|
||||||
params['message_thread_id'] = post.topic_id
|
params['message_thread_id'] = post.topic_id
|
||||||
|
|
||||||
|
|
@ -395,19 +401,21 @@ class Scheduler:
|
||||||
async with http_session.post(url, json=params, timeout=30) as resp:
|
async with http_session.post(url, json=params, timeout=30) as resp:
|
||||||
if resp.status == 200:
|
if resp.status == 200:
|
||||||
result_data = await resp.json()
|
result_data = await resp.json()
|
||||||
message_id = result_data['result']['message_id']
|
# message_id остаётся от документа или берём от фото
|
||||||
|
if not message_id:
|
||||||
|
message_id = result_data['result']['message_id']
|
||||||
else:
|
else:
|
||||||
error_text = await resp.text()
|
error_text = await resp.text()
|
||||||
raise Exception(f"Telegram API {resp.status}: {error_text}")
|
logger.warning(f"Не удалось отправить фото: {error_text}")
|
||||||
else:
|
|
||||||
# Только текст
|
# 3. Если ни документа ни фото — только текст
|
||||||
|
if not post.document_file_id and not post.photo_file_id:
|
||||||
url = f"{base_url}/sendMessage"
|
url = f"{base_url}/sendMessage"
|
||||||
params = {
|
params = {
|
||||||
'chat_id': ADMIN_CHAT_ID,
|
'chat_id': ADMIN_CHAT_ID,
|
||||||
'text': post.text,
|
'text': post.text,
|
||||||
'parse_mode': 'HTML'
|
'parse_mode': 'HTML'
|
||||||
}
|
}
|
||||||
# Не добавляем message_thread_id для general (1) — это общий чат
|
|
||||||
if post.topic_id and post.topic_id > 1:
|
if post.topic_id and post.topic_id > 1:
|
||||||
params['message_thread_id'] = post.topic_id
|
params['message_thread_id'] = post.topic_id
|
||||||
|
|
||||||
|
|
@ -428,6 +436,7 @@ class Scheduler:
|
||||||
|
|
||||||
for user in users:
|
for user in users:
|
||||||
try:
|
try:
|
||||||
|
# Документ + фото отдельными сообщениями
|
||||||
if post.document_file_id:
|
if post.document_file_id:
|
||||||
url = f"{base_url}/sendDocument"
|
url = f"{base_url}/sendDocument"
|
||||||
params = {
|
params = {
|
||||||
|
|
|
||||||
18
web/app.py
18
web/app.py
|
|
@ -788,11 +788,17 @@ async def api_create_scheduled_post(
|
||||||
# Парсим время
|
# Парсим время
|
||||||
scheduled_dt = datetime.fromisoformat(scheduled_time)
|
scheduled_dt = datetime.fromisoformat(scheduled_time)
|
||||||
|
|
||||||
# Если есть timezone - конвертируем в UTC
|
# Если нет timezone — считаем что это локальное время (UTC+4)
|
||||||
if scheduled_dt.tzinfo is not None:
|
# и конвертируем в UTC для scheduler
|
||||||
|
if scheduled_dt.tzinfo is None:
|
||||||
from datetime import timezone as tz
|
from datetime import timezone as tz
|
||||||
|
local_tz = tz(timedelta(hours=4)) # Ульяновск UTC+4
|
||||||
|
scheduled_dt = scheduled_dt.replace(tzinfo=local_tz) # Помечаем как локальное
|
||||||
|
scheduled_dt = scheduled_dt.astimezone(tz.utc).replace(tzinfo=None) # Конвертируем в UTC
|
||||||
|
logger.info(f"⏰ Время конвертирована из локального в UTC: {scheduled_dt}")
|
||||||
|
else:
|
||||||
scheduled_dt = scheduled_dt.astimezone(tz.utc).replace(tzinfo=None)
|
scheduled_dt = scheduled_dt.astimezone(tz.utc).replace(tzinfo=None)
|
||||||
logger.info(f"⏰ Время конвертирована в UTC: {scheduled_dt}")
|
logger.info(f"⏰ Время уже с timezone, конвертирована в UTC: {scheduled_dt}")
|
||||||
|
|
||||||
# Проверяем что время в будущем (по UTC)
|
# Проверяем что время в будущем (по UTC)
|
||||||
if scheduled_dt < datetime.utcnow():
|
if scheduled_dt < datetime.utcnow():
|
||||||
|
|
@ -816,7 +822,7 @@ async def api_create_scheduled_post(
|
||||||
async with aiohttp.ClientSession() as session:
|
async with aiohttp.ClientSession() as session:
|
||||||
url = f"https://api.telegram.org/bot{config.BOT_TOKEN}/sendPhoto"
|
url = f"https://api.telegram.org/bot{config.BOT_TOKEN}/sendPhoto"
|
||||||
data = aiohttp.FormData()
|
data = aiohttp.FormData()
|
||||||
data.add_field('chat_id', config.ADMIN_USER_ID)
|
data.add_field('chat_id', str(config.ADMIN_USER_ID))
|
||||||
data.add_field('photo', open(temp_path, 'rb'), filename=photo.filename)
|
data.add_field('photo', open(temp_path, 'rb'), filename=photo.filename)
|
||||||
data.add_field('caption', 'Preview')
|
data.add_field('caption', 'Preview')
|
||||||
|
|
||||||
|
|
@ -851,8 +857,8 @@ async def api_create_scheduled_post(
|
||||||
async with aiohttp.ClientSession() as session:
|
async with aiohttp.ClientSession() as session:
|
||||||
url = f"https://api.telegram.org/bot{config.BOT_TOKEN}/sendDocument"
|
url = f"https://api.telegram.org/bot{config.BOT_TOKEN}/sendDocument"
|
||||||
data = aiohttp.FormData()
|
data = aiohttp.FormData()
|
||||||
data.add_field('chat_id', config.ADMIN_USER_ID)
|
data.add_field('chat_id', str(config.ADMIN_USER_ID))
|
||||||
|
|
||||||
with open(temp_path, 'rb') as doc_file:
|
with open(temp_path, 'rb') as doc_file:
|
||||||
data.add_field('document', doc_file, filename=document.filename)
|
data.add_field('document', doc_file, filename=document.filename)
|
||||||
data.add_field('caption', 'Document preview')
|
data.add_field('caption', 'Document preview')
|
||||||
|
|
|
||||||
|
|
@ -163,9 +163,7 @@
|
||||||
if (file) {
|
if (file) {
|
||||||
nameSpan.textContent = file.name;
|
nameSpan.textContent = file.name;
|
||||||
preview.style.display = 'block';
|
preview.style.display = 'block';
|
||||||
// Очищаем фото если выбран документ
|
// НЕ очищаем фото — можно прикрепить и то и другое
|
||||||
document.getElementById('postPhoto').value = '';
|
|
||||||
document.getElementById('preview').style.display = 'none';
|
|
||||||
} else {
|
} else {
|
||||||
preview.style.display = 'none';
|
preview.style.display = 'none';
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue