From d7e105d986921fed9fe62df29bd64f7e7c36b408 Mon Sep 17 00:00:00 2001 From: gitadmin Date: Sun, 30 Aug 2026 11:37:19 +0300 Subject: [PATCH] =?UTF-8?q?[ZILANT]=20=D0=BE=D1=82=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D1=8F=D1=82=D1=8C=20=D0=BA=D0=B0=D1=80=D1=82=D0=B8=D0=BD?= =?UTF-8?q?=D0=BA=D0=B8=20=D0=BF=D1=80=D0=B8=20=D0=BF=D0=BE=D1=81=D1=82?= =?UTF-8?q?=D0=B5=20=D1=81=D0=BE=D0=B1=D1=8B=D1=82=D0=B8=D0=B9=20=D0=BA?= =?UTF-8?q?=D0=B0=D0=BA=20=D1=84=D0=B0=D0=B9=D0=BB,=20=D0=B0=20=D0=BD?= =?UTF-8?q?=D0=B5=20=D0=BA=D0=B0=D0=BA=20URL;=20=D0=B4=D0=B5=D0=BB=D0=B0?= =?UTF-8?q?=D0=B5=D0=BC=20=D0=BA=D0=B0=D0=BA=20=D0=BF=D1=80=D0=B8=20=D1=80?= =?UTF-8?q?=D0=B5=D0=BF=D0=BE=D1=81=D1=82=D0=B5=20=D0=92=D0=9A=20=D0=BF?= =?UTF-8?q?=D0=BE=D1=81=D1=82=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .cursor/rules/version-and-docs.mdc | 2 +- README.md | 2 +- VERSION | 2 +- docs/CHANGELOG.md | 6 ++++ evtg_publish.py | 53 +++++++++++++++++++++++++++--- 5 files changed, 57 insertions(+), 8 deletions(-) diff --git a/.cursor/rules/version-and-docs.mdc b/.cursor/rules/version-and-docs.mdc index 90f474a..a1204a7 100644 --- a/.cursor/rules/version-and-docs.mdc +++ b/.cursor/rules/version-and-docs.mdc @@ -20,4 +20,4 @@ alwaysApply: true 5. Не поднимать версию за косметические правки без изменения поведения. -Текущая базовая версия: **1.0.2**. +Текущая базовая версия: **1.0.3**. diff --git a/README.md b/README.md index faff1a7..381a7e1 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Zilant / VOLK — Telegram poster и подписки -**Версия:** 1.0.2 ([`VERSION`](VERSION)) +**Версия:** 1.0.3 ([`VERSION`](VERSION)) Автоматическая публикация постов и событий в Telegram-канал, веб-редактор, бот подписок с сезонными deep link. diff --git a/VERSION b/VERSION index 6d7de6e..21e8796 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.2 +1.0.3 diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 6c89216..086c982 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -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 diff --git a/evtg_publish.py b/evtg_publish.py index 07030a1..8627bc3 100644 --- a/evtg_publish.py +++ b/evtg_publish.py @@ -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()