fix(publisher): медиа постов не публиковалось в Telegram — контейнер монтировал media/media вместо media

Причина: compose монтировал ../../media/media:/srv/publisher/media, а краулер
с 2026-09-12 качает файлы в media/<file> (новая раскладка). В контейнере
Path(media/<file>).exists() = False → медиа молча пропускалось, уходил только
текст (пост #1017).

Фикс: монтировать весь ../../media + _resolve_media() в publisher
(пробует media/<file>, media/media/<basename>). GoToSocial тоже.
Change fix-media-mount (skip_specs: багфикс), e2e: media_message_id задан,
тестовые сообщения удалены.
This commit is contained in:
kpa39l
2026-09-14 18:29:54 +00:00
parent a6cf605f52
commit ee2f8ac61a
6 changed files with 207 additions and 8 deletions
+28 -4
View File
@@ -74,6 +74,28 @@ def healthz():
}
def _resolve_media(media: str | None) -> str | None:
"""Находит реальный путь медиа-файла в контейнере (CWD /srv/publisher).
Пробует варианты в порядке приоритета:
1. media как есть -> /srv/publisher/media/<file> (новая раскладка)
2. media/media/<basename> -> старая раскладка (media/media/<file>)
Возвращает существующий путь или None (медиа молча пропускается).
"""
if not media:
return None
base = Path(media).name
# card.media из веба — относительный 'media/<file>' → резолвится от CWD /srv/publisher
cands = [Path(media), Path("media") / base, Path("media/media") / base]
for c in cands:
try:
if c.exists() and c.is_file():
return str(c)
except OSError:
continue
return None
def _publish_gotosocial(card: Card, ch: str) -> ChannelResult:
"""Публикует карточку в GoToSocial (Mastodon API). Возвращает ChannelResult.
@@ -83,8 +105,9 @@ def _publish_gotosocial(card: Card, ch: str) -> ChannelResult:
res = ChannelResult()
try:
media_ids: list[str] = []
if card.media and Path(card.media).exists():
media_ids.append(gotosocial.upload_media(card.media))
media_path = _resolve_media(card.media)
if media_path:
media_ids.append(gotosocial.upload_media(media_path))
sid = gotosocial.post_status(
text=card.text,
media_ids=media_ids or None,
@@ -122,9 +145,10 @@ def publish(req: PublishRequest):
for ch in channels:
res = ChannelResult()
try:
if req.card.media and Path(req.card.media).exists():
media_path = _resolve_media(req.card.media)
if media_path:
# медиа первым (caption короткий: первые 1000 символов, т.к. лимит 1024)
media_msg = telegram.send_media(ch, req.card.media, caption=req.card.text[:1000])
media_msg = telegram.send_media(ch, media_path, caption=req.card.text[:1000])
res.media_message_id = media_msg
# ПОЛНЫЙ текст отдельным сообщением (без предпросмотра ссылки)
msg = telegram.send_message(ch, req.card.text)
+5 -4
View File
@@ -14,10 +14,11 @@ services:
extra_hosts:
- "host.docker.internal:host-gateway"
volumes:
# медиа для карточек: веб шлёт media/<file> (media_path из БД).
# Физически файлы лежат в /opt/vesti/media/media/ (вложенный каталог, см. download_media в краулере).
# Монтируем именно внутренний каталог, чтобы Path('media/<file>') в контейнере (от WORKDIR /srv/publisher) попал в файл.
- ../../media/media:/srv/publisher/media:ro
# ВЕСЬ каталог медиа (не media/media): краулер с 2026-09-12 качает в
# media/<file>, старые лежали в media/media/<file>. Обе раскладки
# доступны в контейнере: /srv/publisher/media/<file> и
# /srv/publisher/media/media/<file>.
- ../../media:/srv/publisher/media:ro
healthcheck:
test: ["CMD", "python", "-c", "import urllib.request;urllib.request.urlopen('http://127.0.0.1:8410/healthz',timeout=4)"]
interval: 30s