diff --git a/docs/update-5.md b/docs/update-5.md new file mode 100644 index 0000000..de4f855 --- /dev/null +++ b/docs/update-5.md @@ -0,0 +1,26 @@ +# Обновление 5 — Нормализация URL картинок + +## Проблема + +Клиент Conversations (и его форки) не отображает OOB-картинки, если URL содержит символ `:` +в path-части (например, `…/1579780545_0:182:3048:1897_…jpg`). + +При парсинге OOB `` клиент интерпретирует `:` как разделитель схемы или порта +и обрезает URL — ссылка становится невалидной, картинка не загружается. + +URL без двоеточий в пути отображаются корректно. + +## Решение + +URL-энкодировать path-часть URL картинки перед сохранением в `NewsItem`. +Символ `:` кодируется как `%3A`. Согласно RFC 3986, percent-encoded символы +эквивалентны оригинальным — CDN-серверы обязаны принимать такие URL. + +## Техническая реализация + +1. В `adapters/sources/rss/fetcher.py` добавить функцию `_normalize_image_url(url: str) -> str` +2. Функция использует `urllib.parse` (стандартная библиотека, без новых зависимостей): + - разобрать URL через `urlparse` + - перекодировать path через `quote(path, safe='/')` — слэши остаются, `:` кодируется + - собрать обратно через `urlunparse` +3. Вызывать `_normalize_image_url` в `_extract_image_url` перед возвратом URL diff --git a/docs/update-6.md b/docs/update-6.md new file mode 100644 index 0000000..02a8389 --- /dev/null +++ b/docs/update-6.md @@ -0,0 +1,21 @@ +# Обновление 6 — Убрать картинку из тела сообщения + +## Контекст + +В update-2 картинка добавлялась двумя способами: +- в XHTML-теле через `

` +- в plain-text fallback через URL картинки первым блоком + +В update-4 добавлен OOB (XEP-0066), который обеспечивает отображение картинки +в клиентах семейства Conversations. Таким образом, `` и URL в fallback +стали избыточными и создают визуальный мусор в клиентах, не рендерящих XHTML. + +## Задача + +Убрать блок картинки из тела сообщения: + +1. В `_build_xhtml` — убрать `



` +2. В `_build_plain` — убрать добавление `image_url` в список блоков + +Поле `image_url` в `NewsItem` и логика его извлечения в fetcher'е остаются — +оно по-прежнему используется для OOB. diff --git a/src/adapters/jabber/news_publisher.py b/src/adapters/jabber/news_publisher.py index 4df9600..3c67d73 100644 --- a/src/adapters/jabber/news_publisher.py +++ b/src/adapters/jabber/news_publisher.py @@ -22,10 +22,7 @@ class JabberNewsPublisher(NewsPublisher): return await self._connection.send_to_room_xhtml(room_jid, plain, xhtml, item.image_url) def _build_plain(self, item: NewsItem) -> str: - blocks = [] - if item.image_url: - blocks.append(item.image_url) - blocks.append(item.title) + blocks = [item.title] if item.summary: blocks.append(item.summary) blocks.append(item.link) @@ -33,10 +30,7 @@ class JabberNewsPublisher(NewsPublisher): def _build_xhtml(self, item: NewsItem) -> str: SEP = "

" - parts = [] - if item.image_url: - parts.append(f'

{SEP}') - parts.append(f'

{item.title}

{SEP}') + parts = [f'

{item.title}

{SEP}'] if item.summary: parts.append(f'

{item.summary}

{SEP}') parts.append(f'

{item.link}

') diff --git a/src/adapters/sources/rss/fetcher.py b/src/adapters/sources/rss/fetcher.py index d5e5c23..389933d 100644 --- a/src/adapters/sources/rss/fetcher.py +++ b/src/adapters/sources/rss/fetcher.py @@ -3,6 +3,7 @@ import logging import re from html import unescape from typing import List, Optional +from urllib.parse import quote, urlparse, urlunparse import feedparser @@ -19,11 +20,18 @@ def _strip_html(text: str) -> str: return unescape(text).strip() +def _normalize_image_url(url: str) -> str: + """URL-энкодирует path-часть, чтобы символы вроде ':' не ломали парсеры клиентов.""" + p = urlparse(url) + return urlunparse(p._replace(path=quote(p.path, safe='/'))) + + def _extract_image_url(entry) -> Optional[str]: - """Возвращает URL первого enclosure с type image/*.""" + """Возвращает нормализованный URL первого enclosure с type image/*.""" for enc in entry.get("enclosures", []): if enc.get("type", "").startswith("image/"): - return enc.get("href") or enc.get("url") + raw = enc.get("href") or enc.get("url") + return _normalize_image_url(raw) if raw else None return None