diff --git a/docs/update-7.md b/docs/update-7.md new file mode 100644 index 0000000..072f4b7 --- /dev/null +++ b/docs/update-7.md @@ -0,0 +1,31 @@ +# Обновление 7 — Пропускать OOB если URL картинки содержит недопустимые символы + +## Контекст + +В update-5 была добавлена нормализация URL картинок: символ `:` в path кодировался как `%3A`. +Выяснилось, что CDN принимает закодированный URL (200 OK), но клиент Conversations +всё равно не отображает картинку — причина в hotlink protection на стороне CDN. +Таким образом, нормализация URL не решает проблему и бесполезна. + +Практическое наблюдение: URL с `:` в path — признак CDN с hotlink protection. +Такие картинки не отобразятся в клиентах в любом случае. +Решение: не добавлять OOB для URL, содержащих `:` в path-части. + +## Задача + +1. В `adapters/sources/rss/fetcher.py`: + - Удалить функцию `_normalize_image_url` и импорты `urllib.parse` + - В `_extract_image_url` проверять raw URL: если path-часть содержит `:` — возвращать `None` + +## Техническая реализация + +Проверка выполняется через `urlparse`: + +```python +from urllib.parse import urlparse + +p = urlparse(url) +if ':' in p.path: + return None +return url +``` diff --git a/src/adapters/sources/rss/fetcher.py b/src/adapters/sources/rss/fetcher.py index 389933d..f7e1169 100644 --- a/src/adapters/sources/rss/fetcher.py +++ b/src/adapters/sources/rss/fetcher.py @@ -3,7 +3,7 @@ import logging import re from html import unescape from typing import List, Optional -from urllib.parse import quote, urlparse, urlunparse +from urllib.parse import urlparse import feedparser @@ -20,18 +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/*. + Возвращает None если URL содержит ':' в path — признак hotlink-защищённого CDN. + """ for enc in entry.get("enclosures", []): if enc.get("type", "").startswith("image/"): raw = enc.get("href") or enc.get("url") - return _normalize_image_url(raw) if raw else None + if not raw: + return None + if ":" in urlparse(raw).path: + return None + return raw return None