[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. Не поднимать версию за косметические правки без изменения поведения. 5. Не поднимать версию за косметические правки без изменения поведения.
Текущая базовая версия: **1.0.2**. Текущая базовая версия: **1.0.3**.
+1 -1
View File
@@ -1,6 +1,6 @@
# Zilant / VOLK — Telegram poster и подписки # Zilant / VOLK — Telegram poster и подписки
**Версия:** 1.0.2 ([`VERSION`](VERSION)) **Версия:** 1.0.3 ([`VERSION`](VERSION))
Автоматическая публикация постов и событий в Telegram-канал, веб-редактор, бот подписок с сезонными deep link. Автоматическая публикация постов и событий в 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/). Формат основан на [Keep a Changelog](https://keepachangelog.com/ru/1.1.0/).
Версия проекта — в файле [`VERSION`](../VERSION) (SemVer). Версия проекта — в файле [`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 ## [1.0.2] - 2026-08-30
### Added ### Added
+48 -5
View File
@@ -6,6 +6,7 @@ import time
import html import html
import httpx import httpx
from datetime import datetime, timezone, timedelta from datetime import datetime, timezone, timedelta
from urllib.parse import urlparse, unquote
from dotenv import load_dotenv from dotenv import load_dotenv
from formatter import get_event_text from formatter import get_event_text
from telegram_relay import bot_api_method_url from telegram_relay import bot_api_method_url
@@ -92,6 +93,39 @@ def prepare_text(text):
return 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): async def tg_post_event(httpx_client, event_data):
"""Публикация одного события""" """Публикация одного события"""
try: try:
@@ -197,15 +231,24 @@ async def tg_post_event(httpx_client, event_data):
if has_image: if has_image:
try: try:
logger.info(f"Попытка отправки фото для события {event_data['number']}: chat_id={CHANNEL_ID}, caption_length={len(initial_text)}, image_url_length={len(image_url)}") logger.info(
photo_payload = { 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, 'chat_id': CHANNEL_ID,
'photo': image_url,
'caption': initial_text, 'caption': initial_text,
'parse_mode': 'HTML', '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: if photo_response.status_code == 200:
photo_result = photo_response.json() photo_result = photo_response.json()