[ZILANT] отправлять картинки при посте событий как файл, а не как URL; делаем как при репосте ВК постов
ci/woodpecker/push/woodpecker Pipeline was successful

This commit is contained in:
2026-08-30 11:37:19 +03:00
parent 352c0da209
commit d7e105d986
5 changed files with 57 additions and 8 deletions
+1 -1
View File
@@ -20,4 +20,4 @@ alwaysApply: true
5. Не поднимать версию за косметические правки без изменения поведения.
Текущая базовая версия: **1.0.2**.
Текущая базовая версия: **1.0.3**.
+1 -1
View File
@@ -1,6 +1,6 @@
# Zilant / VOLK — Telegram poster и подписки
**Версия:** 1.0.2 ([`VERSION`](VERSION))
**Версия:** 1.0.3 ([`VERSION`](VERSION))
Автоматическая публикация постов и событий в Telegram-канал, веб-редактор, бот подписок с сезонными deep link.
+1 -1
View File
@@ -1 +1 @@
1.0.2
1.0.3
+6
View File
@@ -3,6 +3,12 @@
Формат основан на [Keep a Changelog](https://keepachangelog.com/ru/1.1.0/).
Версия проекта — в файле [`VERSION`](../VERSION) (SemVer).
## [1.0.3] - 2026-08-30
### Fixed
- Публикация событий (`evtg_publish.py`): картинка скачивается на сервере и уходит в `sendPhoto` файлом, как у постов VK. Раньше в Bot API передавался URL (`http://reg.konvent.ru/...`), Telegram не мог его забрать (`failed to get HTTP URL content`) и пост уходил текстом.
## [1.0.2] - 2026-08-30
### Added
+48 -5
View File
@@ -6,6 +6,7 @@ import time
import html
import httpx
from datetime import datetime, timezone, timedelta
from urllib.parse import urlparse, unquote
from dotenv import load_dotenv
from formatter import get_event_text
from telegram_relay import bot_api_method_url
@@ -92,6 +93,39 @@ def prepare_text(text):
return text
def _filename_from_image_url(image_url):
path = unquote(urlparse(image_url).path)
name = os.path.basename(path) or "image.jpg"
if "." not in name:
name = f"{name}.jpg"
return name
async def download_image(image_url, httpx_client):
"""Скачивает картинку самим сервером (как tg_publish), не отдаёт URL Telegram.
sendPhoto с photo=http://... Telegram качает сам и часто отвечает
«failed to get HTTP URL content» (http, недоступность с DC Telegram).
"""
logger.info(f"Скачивание изображения: {image_url}")
started = time.time()
response = await httpx_client.get(
image_url,
timeout=httpx.Timeout(connect=10.0, read=60.0, write=30.0, pool=10.0),
)
response.raise_for_status()
image_data = response.content
content_type = (response.headers.get("content-type") or "image/jpeg").split(";")[0].strip()
if not content_type.startswith("image/"):
content_type = "image/jpeg"
logger.info(
f"Изображение скачано за {time.time() - started:.2f} с, "
f"размер: {len(image_data)} байт, type={content_type}"
)
return image_data, content_type, _filename_from_image_url(image_url)
async def tg_post_event(httpx_client, event_data):
"""Публикация одного события"""
try:
@@ -197,15 +231,24 @@ async def tg_post_event(httpx_client, event_data):
if has_image:
try:
logger.info(f"Попытка отправки фото для события {event_data['number']}: chat_id={CHANNEL_ID}, caption_length={len(initial_text)}, image_url_length={len(image_url)}")
photo_payload = {
logger.info(
f"Попытка отправки фото для события {event_data['number']}: "
f"chat_id={CHANNEL_ID}, caption_length={len(initial_text)}, "
f"image_url={image_url}"
)
image_data, content_type, filename = await download_image(image_url, httpx_client)
photo_data = {
'chat_id': CHANNEL_ID,
'photo': image_url,
'caption': initial_text,
'parse_mode': 'HTML',
'disable_notification': PUBLISH_SILENTLY
'disable_notification': 'true' if PUBLISH_SILENTLY else 'false',
}
photo_response = await httpx_client.post(send_photo_url, json=photo_payload)
photo_files = {
'photo': (filename, image_data, content_type),
}
photo_response = await httpx_client.post(
send_photo_url, data=photo_data, files=photo_files
)
if photo_response.status_code == 200:
photo_result = photo_response.json()