[ZILANT] коррекция логики проверки добавленных ссылок
ci/woodpecker/push/woodpecker Pipeline was successful

This commit is contained in:
2026-09-02 22:49:03 +03:00
parent f74953e082
commit 87ccd23e96
7 changed files with 25 additions and 40 deletions
+1 -1
View File
@@ -20,4 +20,4 @@ alwaysApply: true
5. Не поднимать версию за косметические правки без изменения поведения. 5. Не поднимать версию за косметические правки без изменения поведения.
Текущая базовая версия: **1.1.3**. Текущая базовая версия: **1.1.4**.
+1 -1
View File
@@ -1,6 +1,6 @@
# Zilant / VOLK — Telegram poster и подписки # Zilant / VOLK — Telegram poster и подписки
**Версия:** 1.1.3 ([`VERSION`](VERSION)) **Версия:** 1.1.4 ([`VERSION`](VERSION))
Автоматическая публикация постов и событий в Telegram-канал, веб-редактор, бот подписок с сезонными deep link. Автоматическая публикация постов и событий в Telegram-канал, веб-редактор, бот подписок с сезонными deep link.
+1 -1
View File
@@ -1 +1 @@
1.1.3 1.1.4
+10
View File
@@ -3,6 +3,16 @@
Формат основан на [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.1.4] - 2026-09-02
### Fixed
- Проверка footer-ссылок после edit: убрано сравнение `min_length` (HTML длиннее plain text от Telegram) — лишние retry, мигание ссылок и обрыв пакетной публикации из UI.
### Changed
- Проверка footer-ссылок: убрано сравнение `min_length` (HTML длиннее plain text от Telegram).
## [1.1.3] - 2026-09-02 ## [1.1.3] - 2026-09-02
### Fixed ### Fixed
+5 -9
View File
@@ -134,7 +134,7 @@ async def download_image(image_url, httpx_client):
async def _edit_event_add_links( async def _edit_event_add_links(
httpx_client, has_image, message_id, final_text, entity_label, expected_urls, min_length httpx_client, has_image, message_id, final_text, entity_label, expected_urls
): ):
"""Edit caption/text со ссылками; повтор до подтверждения всех expected_urls в text_link.""" """Edit caption/text со ссылками; повтор до подтверждения всех expected_urls в text_link."""
await asyncio.sleep(EDIT_LINKS_INITIAL_DELAY_SEC) await asyncio.sleep(EDIT_LINKS_INITIAL_DELAY_SEC)
@@ -179,9 +179,7 @@ async def _edit_event_add_links(
result = data.get('result') or {} result = data.get('result') or {}
result_text = result.get(field) or "" result_text = result.get(field) or ""
entities = result.get(entities_field) or [] entities = result.get(entities_field) or []
if published_message_has_expected_links( if published_message_has_expected_links(entities, expected_urls):
entities, expected_urls, result_text=result_text, min_length=min_length
):
logger.info( logger.info(
f"Ссылки добавлены для {entity_label} " f"Ссылки добавлены для {entity_label} "
f"(попытка {attempt}/{EDIT_LINKS_MAX_ATTEMPTS})" f"(попытка {attempt}/{EDIT_LINKS_MAX_ATTEMPTS})"
@@ -191,8 +189,7 @@ async def _edit_event_add_links(
logger.warning( logger.warning(
f"edit ok, но footer-ссылки не подтверждены " f"edit ok, но footer-ссылки не подтверждены "
f"(попытка {attempt}/{EDIT_LINKS_MAX_ATTEMPTS}) для {entity_label}; " f"(попытка {attempt}/{EDIT_LINKS_MAX_ATTEMPTS}) для {entity_label}; "
f"ожидались {expected_urls}, найдены text_link: {found}, " f"ожидались {expected_urls}, найдены text_link: {found}"
f"len(text)={len(result_text)}, min_len={min_length}"
) )
else: else:
error_code = data.get('error_code') error_code = data.get('error_code')
@@ -548,7 +545,6 @@ async def tg_post_event(httpx_client, event_data):
expected_urls.append( expected_urls.append(
subscription_start_link(RESPONDER_BOT_NAME, "event", message_id) subscription_start_link(RESPONDER_BOT_NAME, "event", message_id)
) )
min_length = len(final_text) - 15
# Проверяем, изменился ли текст. Если нет - не редактируем сообщение # Проверяем, изменился ли текст. Если нет - не редактируем сообщение
if final_text == initial_text: if final_text == initial_text:
@@ -558,12 +554,12 @@ async def tg_post_event(httpx_client, event_data):
entity_label = f"события {event_data['number']}" entity_label = f"события {event_data['number']}"
links_ok = await _edit_event_add_links( links_ok = await _edit_event_add_links(
httpx_client, message_is_photo, message_id, final_text, entity_label, httpx_client, message_is_photo, message_id, final_text, entity_label,
expected_urls, min_length, expected_urls,
) )
if not links_ok and message_is_photo: if not links_ok and message_is_photo:
links_ok = await _edit_event_add_links( links_ok = await _edit_event_add_links(
httpx_client, False, message_id, final_text, entity_label, httpx_client, False, message_id, final_text, entity_label,
expected_urls, min_length, expected_urls,
) )
if not links_ok: if not links_ok:
logger.error( logger.error(
+3 -19
View File
@@ -72,27 +72,16 @@ def extract_text_link_urls(entities) -> list:
return urls return urls
def published_message_has_expected_links( def published_message_has_expected_links(entities, expected_urls) -> bool:
entities,
expected_urls,
*,
result_text: str | None = None,
min_length: int | None = None,
) -> bool:
""" """
Проверка, что в сообщении есть именно footer-ссылки публикации. Проверка, что в сообщении есть именно footer-ссылки публикации.
Нельзя проверять «любой text_link» или слова «Инфо»/«Подписка» в тексте: Сравнение только по URL в text_link entities (plain text короче HTML).
в теле события могут быть свои <a href> из replace_vk_links.
""" """
expected_urls = [u for u in (expected_urls or []) if u] expected_urls = [u for u in (expected_urls or []) if u]
if not expected_urls: if not expected_urls:
return True return True
if min_length is not None and result_text is not None:
if len(result_text) < min_length:
return False
found = set(extract_text_link_urls(entities)) found = set(extract_text_link_urls(entities))
return all(url in found for url in expected_urls) return all(url in found for url in expected_urls)
@@ -100,12 +89,7 @@ def published_message_has_expected_links(
def published_message_has_links(text: str, entities=None, expected_urls=None) -> bool: def published_message_has_links(text: str, entities=None, expected_urls=None) -> bool:
"""Проверка footer-ссылок; expected_urls обязателен при вызове из publisher.""" """Проверка footer-ссылок; expected_urls обязателен при вызове из publisher."""
if expected_urls is not None: if expected_urls is not None:
return published_message_has_expected_links( return published_message_has_expected_links(entities, expected_urls)
entities,
expected_urls,
result_text=text,
min_length=None,
)
return bool(extract_text_link_urls(entities)) return bool(extract_text_link_urls(entities))
+4 -9
View File
@@ -156,7 +156,7 @@ async def download_image(image_url, httpx_client):
async def _edit_post_add_links( async def _edit_post_add_links(
bot, message_id, message_has_image, final_text, vk_post_id, expected_urls, min_length bot, message_id, message_has_image, final_text, vk_post_id, expected_urls
): ):
""" """
Второй шаг публикации: editMessageCaption/Text со ссылками. Второй шаг публикации: editMessageCaption/Text со ссылками.
@@ -186,9 +186,7 @@ async def _edit_post_add_links(
published_text = edited.text or "" published_text = edited.text or ""
entities = edited.entities or [] entities = edited.entities or []
if published_message_has_expected_links( if published_message_has_expected_links(entities, expected_urls):
entities, expected_urls, result_text=published_text, min_length=min_length
):
logger.info( logger.info(
f"Ссылки добавлены для записи VK ID {vk_post_id} " f"Ссылки добавлены для записи VK ID {vk_post_id} "
f"(попытка {attempt}/{EDIT_LINKS_MAX_ATTEMPTS})" f"(попытка {attempt}/{EDIT_LINKS_MAX_ATTEMPTS})"
@@ -199,8 +197,7 @@ async def _edit_post_add_links(
logger.warning( logger.warning(
f"editMessage* ok, но footer-ссылки не подтверждены " f"editMessage* ok, но footer-ссылки не подтверждены "
f"(попытка {attempt}/{EDIT_LINKS_MAX_ATTEMPTS}) для VK ID {vk_post_id}; " f"(попытка {attempt}/{EDIT_LINKS_MAX_ATTEMPTS}) для VK ID {vk_post_id}; "
f"ожидались {expected_urls}, найдены text_link: {found}, " f"ожидались {expected_urls}, найдены text_link: {found}"
f"len(text)={len(published_text)}, min_len={min_length}"
) )
except TimedOut as e: except TimedOut as e:
if attempt >= EDIT_LINKS_MAX_ATTEMPTS: if attempt >= EDIT_LINKS_MAX_ATTEMPTS:
@@ -534,11 +531,9 @@ async def publish_to_tg(vk_post_id):
expected_urls.append( expected_urls.append(
subscription_start_link(RESPONDER_BOT_NAME, "post", message_id) subscription_start_link(RESPONDER_BOT_NAME, "post", message_id)
) )
min_length = len(final_text) - 15
if not await _edit_post_add_links( if not await _edit_post_add_links(
bot, message_id, message_has_image, final_text, vk_post_id, bot, message_id, message_has_image, final_text, vk_post_id,
expected_urls, min_length, expected_urls,
): ):
logger.error( logger.error(
f"Запись VK ID {vk_post_id}: сообщение отправлено (id={message_id}), " f"Запись VK ID {vk_post_id}: сообщение отправлено (id={message_id}), "