refactor(render): этап 5b — зарегистрированные фиксы медиа-таблицы §3.13/§3.14 (#32)

Поверх байт-в-байт 5a — только фиксы реестра:
- §3.14: закрывающий </div> эмитится в КАЖДОЙ ветке media-рендера (раньше
  несбалансированный div в конце фрагмента авто-закрывался bleach позже). На
  фрагмент-оракуле изменились ровно 2 кейса (file_unique_id_none,
  webpage_without_photo); в feed-голденах — чисто РЕЛОКАЦИЯ </div> с конца поста
  на место сразу после пустого media-div (счётчик </div> не меняется, контент
  идентичен). Затронуты каналы с webpage-без-фото (theyforcedme без изменений).
- §3.13: гард >100MB теперь на ЛЮБОЙ media-объект (не только message.video);
  collection-only, байты фида не трогает.

test_stage5b_media_fixes.py (14 тестов). Полный сюит 427 passed, PYTHONHASHSEED
1/42. Golden строго по §3 (проверял независимо: net-теги 0, только </div>-релокация).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-06 18:26:50 +03:00
parent 78e9bc2583
commit c8e741ca41
9 changed files with 177 additions and 34 deletions
+14 -20
View File
@@ -973,7 +973,6 @@ class PostParser:
# Guard: channel_username may be None for private chats without a username
if not channel_username:
logger.warning(f"Could not generate media URL for message {message.id}: channel username is missing.")
content_media.append('</div>')
else:
file = f"{channel_username}/{message.id}/{file_unique_id}"
digest = generate_media_digest(file)
@@ -1004,7 +1003,11 @@ class PostParser:
elif kind == 'img_200_sticker':
ctx.emoji = getattr(message.sticker, 'emoji', '')
content_media.extend(renderer(ctx))
content_media.append('</div>')
# Registry §3.14: close the message-media container in EVERY branch. It used
# to be closed only when a URL was built (or the username guard fired), so a
# None file_unique_id (e.g. WEB_PAGE without photo) left an open <div> that
# html5lib later swallowed the following posts into.
content_media.append('</div>')
if webpage := getattr(message, "web_page", None): # Web page preview
if webpage_html := self._format_webpage(webpage, message):
@@ -1365,27 +1368,18 @@ class PostParser:
return
if message.media:
# Skip large videos - they shouldn't be cached permanently.
# 5a keeps this message.video-only guard verbatim; registry §3.13
# generalises the >100MB rule to every selected object in 5b.
if message.video and message.video.file_size and message.video.file_size > 100 * 1024 * 1024:
return
# Object selection now goes through the single MEDIA_SOURCES table
# instead of the old truthy-attribute if/elif ladder. paid_media has no
# table entry and is deliberately NOT collected (paid content).
# Object selection goes through the single MEDIA_SOURCES table instead
# of the old truthy-attribute if/elif ladder. paid_media has no table
# entry and is deliberately NOT collected (paid content).
selector = MEDIA_SOURCES.get(message.media)
selected_obj = selector(message)[0] if selector is not None else None
# The message.video guard above does not cover the Kurigram 2.2.23
# sources (live photo, story video, poll description video) — apply the
# same "don't cache large videos" rule to them (5b unifies this — §3.13).
if message.media in (MessageMediaType.LIVE_PHOTO,
MessageMediaType.STORY,
MessageMediaType.POLL):
file_size = getattr(selected_obj, 'file_size', None)
if isinstance(file_size, int) and file_size > 100 * 1024 * 1024:
return
# Registry §3.13: the ">100MB don't cache" rule applies to ANY selected
# media object, not just message.video (the old code guarded only the
# video type here, plus the newer live_photo/story/poll sources).
file_size = getattr(selected_obj, 'file_size', None)
if isinstance(file_size, int) and file_size > 100 * 1024 * 1024:
return
file_unique_id = getattr(selected_obj, 'file_unique_id', '') or ''
@@ -982,33 +982,36 @@
<hr class="post-divider">
<div class="message-body"><div class="post">
<div class="message-media">
</div>
<br>
Я тут одним днем был в Екатеринбурге. На конференции по кибербезопасности. На уральском ТВ записали короткое интервью. Не для экспертов, для обычных жителей планеты Земля - что такое кибербез простыми словами, какие угрозы сейчас и что делать - быть может кому-то будет полезно. <br><br>*** по каким-то мистическим причинам, не всегда с мобилы проигрывается, с десктопа - точно работает. Не знаю, почему. <br><br>p.s. На Мэта Деймона времени не хватило (с) :))<br><br><a href="https://www.obltv.ru/broadcasting/programs/479443-sobytija_akcent/releases/4840574-evgeniy-chereshnev-seychas-khakery-eto-ne-studenty-idealisty-a-organizovannye-nayemniki/" target="_blank">https://www.obltv.ru/broadcasting/programs/479443-sobytija_akcent/releases/4840574-evgeniy-chereshnev-seychas-khakery-eto-ne-studenty-idealisty-a-organizovannye-nayemniki/</a>
<br>
</div><br></div>
<div class="message-footer"><br>
<span class="reaction">👍 867&nbsp;&nbsp;</span><span class="reaction">❤ 233&nbsp;&nbsp;</span><span class="reaction">🔥 51&nbsp;&nbsp;</span><span class="reaction">👏 42&nbsp;&nbsp;</span><span class="reaction">🦄 10&nbsp;&nbsp;</span><span class="reaction">🎉 5&nbsp;&nbsp;</span><span class="reaction">💩 4&nbsp;&nbsp;</span><span class="reaction">🥰 3&nbsp;&nbsp;</span><span class="reaction">😁 3&nbsp;&nbsp;</span><span class="reaction">🌚 2&nbsp;&nbsp;</span>&nbsp;&nbsp;|&nbsp;&nbsp;<span class="views">121878 👁</span>&nbsp;&nbsp;|&nbsp;&nbsp;<span class="date">20/02/24, 14:01:23</span>&nbsp;&nbsp;|&nbsp;&nbsp;<span class="message-id">#306</span><br><a href="tg://resolve?domain=bladerunnerblues&amp;post=306">Open in Telegram</a>&nbsp;|&nbsp;<a href="https://t.me/bladerunnerblues/306">Open in Web</a>
<br><div class="message-flags"> 🏷 link </div></div></div>
<br><div class="message-flags"> 🏷 link </div></div>
<hr class="post-divider">
<div class="message-body"><div class="post">
<div class="message-media">
</div>
<br>
<b>[ХОРОШИЕ НОВОСТИ ОБ ИННОВАЦИЯХ НА НЕСКОЛЬКО МИЛЛИАРДОВ ЗА ГОД И ДЕТЯХ, РОЖДЕННЫХ В СССР]</b><br><br>Дорогой экипаж!<br><br>Вдохновения и мотивации пост.<br>Не собирался писать именно это и так эмоционально, но потом перечитал и решил, что не буду редактировать.<br>И, даже если кто-то отпишется, – я никого не держу. Просто в это турбулентное время, хочется продолжать дарить вам надежду в лучшее, а не поощрять самоуничижение, как это делают многие.<br> <br>Хочу констатировать факты: не все уехали, не все плохо, нет, мы умеем делать сильные инженерные рывки в России (а не только в ВПК), нам есть, чем гордится и да, я считаю, что мы единый народ. <br>Хочу, чтобы кому-то этот пост помог улыбнуться и ступать легко и уверенно. <br><br><a href="https://blog.cheresh.me/2024/02/20/billions-in-innovations-and-ussr/" target="_blank">https://blog.cheresh.me/2024/02/20/billions-in-innovations-and-ussr/</a><br><br>P.S. Репосты приветствуются. А вот воровать не надо. Кто ворует мои посты - вы выглядите не очень умно:) Вы думаете, люди не видят, что ли?:) Карма is a bitch.
<br>
</div><br></div>
<div class="message-footer"><br>
<span class="reaction">👍 2200&nbsp;&nbsp;</span><span class="reaction">❤ 916&nbsp;&nbsp;</span><span class="reaction">🔥 408&nbsp;&nbsp;</span><span class="reaction">🍾 70&nbsp;&nbsp;</span><span class="reaction">⚡ 23&nbsp;&nbsp;</span><span class="reaction">🤣 16&nbsp;&nbsp;</span><span class="reaction">🥰 12&nbsp;&nbsp;</span><span class="reaction">👌 11&nbsp;&nbsp;</span><span class="reaction">👎 10&nbsp;&nbsp;</span><span class="reaction">👻 5&nbsp;&nbsp;</span><span class="reaction">🥱 3&nbsp;&nbsp;</span>&nbsp;&nbsp;|&nbsp;&nbsp;<span class="views">690677 👁</span>&nbsp;&nbsp;|&nbsp;&nbsp;<span class="date">20/02/24, 10:10:22</span>&nbsp;&nbsp;|&nbsp;&nbsp;<span class="message-id">#305</span><br><a href="tg://resolve?domain=bladerunnerblues&amp;post=305">Open in Telegram</a>&nbsp;|&nbsp;<a href="https://t.me/bladerunnerblues/305">Open in Web</a>
<br><div class="message-flags"> 🏷 link </div></div></div>
<br><div class="message-flags"> 🏷 link </div></div>
<hr class="post-divider">
<div class="message-body"><div class="post">
<div class="message-media">
</div>
<br>
Экипаж!<br><br>Менять мир непросто. Иногда нам нужна правильная музыка. Приказ по радиорубке - включаем с утра на всех палубах и заряжаемся. Нас ждет прыжок в созвездие Ориона. <br><br><a href="https://youtu.be/9N_AinKeT_g?si=SFAulfGSNuGmh9QU" target="_blank">https://youtu.be/9N_AinKeT_g?si=SFAulfGSNuGmh9QU</a><br><br>P.S. если сегодня будете где-то слышать этот трек - знайте, что его поставил ваш брат или сестра с этого корабля:) и улыбнитесь:) <br>с пятницей!
<br>
</div><br></div>
<div class="message-footer"><br>
<span class="reaction">👍 1208&nbsp;&nbsp;</span><span class="reaction">❤ 447&nbsp;&nbsp;</span><span class="reaction">🔥 255&nbsp;&nbsp;</span><span class="reaction">❤‍🔥 55&nbsp;&nbsp;</span><span class="reaction">🫡 49&nbsp;&nbsp;</span><span class="reaction">😁 37&nbsp;&nbsp;</span><span class="reaction">🤔 9&nbsp;&nbsp;</span><span class="reaction">🤷‍♂ 6&nbsp;&nbsp;</span><span class="reaction">🗿 5&nbsp;&nbsp;</span><span class="reaction">🤡 4&nbsp;&nbsp;</span><span class="reaction">👾 4&nbsp;&nbsp;</span>&nbsp;&nbsp;|&nbsp;&nbsp;<span class="views">110203 👁</span>&nbsp;&nbsp;|&nbsp;&nbsp;<span class="date">16/02/24, 05:23:23</span>&nbsp;&nbsp;|&nbsp;&nbsp;<span class="message-id">#304</span><br><a href="tg://resolve?domain=bladerunnerblues&amp;post=304">Open in Telegram</a>&nbsp;|&nbsp;<a href="https://t.me/bladerunnerblues/304">Open in Web</a>
<br><div class="message-flags"> 🏷 link </div></div></div>
<br><div class="message-flags"> 🏷 link </div></div>
<hr class="post-divider">
<div class="message-body"><div class="post">
<div class="message-media">
@@ -1087,13 +1090,14 @@
<hr class="post-divider">
<div class="message-body"><div class="post">
<div class="message-media">
</div>
<br>
<b>[ПРОГНОЗЫ 2024, Часть 1/14: Выборы на Тайване] <br><br></b>Дорогой экипаж! <b><br></b>Завтра очень важный день для планеты Земля - пройдут выборы президента Тайваня. Почему они критичны для всех и каждого и причем тут Искусственный Интеллект и триллионы долларов - постарался описать максимально коротко. Прогнозы делать - дело неблагодарное, но я решил начать цикл постов о том, что нас ждет в 2024, что важно и что имеет все шансы навсегда изменить мир. <br><br><a href="https://blog.cheresh.me/2024/01/12/really-unreal-forecasts-2024_114/" target="_blank">https://blog.cheresh.me/2024/01/12/really-unreal-forecasts-2024_114/</a>
<br>
</div><br></div>
<div class="message-footer"><br>
<span class="reaction">👍 3107&nbsp;&nbsp;</span><span class="reaction">❤ 788&nbsp;&nbsp;</span><span class="reaction">🔥 382&nbsp;&nbsp;</span><span class="reaction">🤔 52&nbsp;&nbsp;</span><span class="reaction">👏 24&nbsp;&nbsp;</span><span class="reaction">⚡ 21&nbsp;&nbsp;</span><span class="reaction">🐳 10&nbsp;&nbsp;</span><span class="reaction">👎 9&nbsp;&nbsp;</span><span class="reaction">😎 9&nbsp;&nbsp;</span><span class="reaction">👌 4&nbsp;&nbsp;</span><span class="reaction">🤣 3&nbsp;&nbsp;</span>&nbsp;&nbsp;|&nbsp;&nbsp;<span class="views">120670 👁</span>&nbsp;&nbsp;|&nbsp;&nbsp;<span class="date">12/01/24, 16:52:43</span>&nbsp;&nbsp;|&nbsp;&nbsp;<span class="message-id">#296</span><br><a href="tg://resolve?domain=bladerunnerblues&amp;post=296">Open in Telegram</a>&nbsp;|&nbsp;<a href="https://t.me/bladerunnerblues/296">Open in Web</a>
<br><div class="message-flags"> 🏷 link </div></div></div>
<br><div class="message-flags"> 🏷 link </div></div>
<hr class="post-divider">
<div class="message-body"><div class="post">
<div class="message-media">
@@ -32,13 +32,14 @@
<description>[ПРОГНОЗЫ 2024, Часть 1/14: Выборы на Тайване] Дорогой экипаж! Завтра очень важный день для планеты Земля - пройдут выборы президента Тайваня. Почему они критичны для всех и каждого и причем тут Искусственный Интеллект и триллионы долларов - постарался описать максимально коротко. Прогнозы делать - дело неблагодарное, но я решил начать цикл постов о том, что нас ждет в 2024, что важно и что имеет все шансы навсегда изменить мир. https://blog.cheresh.me/2024/01/12/really-unreal-forecasts-2024_114/</description>
<content:encoded><![CDATA[<div class="message-body"><div class="post">
<div class="message-media">
</div>
<br>
<b>[ПРОГНОЗЫ 2024, Часть 1/14: Выборы на Тайване] <br><br></b>Дорогой экипаж! <b><br></b>Завтра очень важный день для планеты Земля - пройдут выборы президента Тайваня. Почему они критичны для всех и каждого и причем тут Искусственный Интеллект и триллионы долларов - постарался описать максимально коротко. Прогнозы делать - дело неблагодарное, но я решил начать цикл постов о том, что нас ждет в 2024, что важно и что имеет все шансы навсегда изменить мир. <br><br><a href="https://blog.cheresh.me/2024/01/12/really-unreal-forecasts-2024_114/" target="_blank">https://blog.cheresh.me/2024/01/12/really-unreal-forecasts-2024_114/</a>
<br>
</div><br></div>
<div class="message-footer"><br>
<span class="reaction">👍 3107&nbsp;&nbsp;</span><span class="reaction">❤ 788&nbsp;&nbsp;</span><span class="reaction">🔥 382&nbsp;&nbsp;</span><span class="reaction">🤔 52&nbsp;&nbsp;</span><span class="reaction">👏 24&nbsp;&nbsp;</span><span class="reaction">⚡ 21&nbsp;&nbsp;</span><span class="reaction">🐳 10&nbsp;&nbsp;</span><span class="reaction">👎 9&nbsp;&nbsp;</span><span class="reaction">😎 9&nbsp;&nbsp;</span><span class="reaction">👌 4&nbsp;&nbsp;</span><span class="reaction">🤣 3&nbsp;&nbsp;</span>&nbsp;&nbsp;|&nbsp;&nbsp;<span class="views">120670 👁</span>&nbsp;&nbsp;|&nbsp;&nbsp;<span class="date">12/01/24, 16:52:43</span>&nbsp;&nbsp;|&nbsp;&nbsp;<span class="message-id">#296</span><br><a href="tg://resolve?domain=bladerunnerblues&amp;post=296">Open in Telegram</a>&nbsp;|&nbsp;<a href="https://t.me/bladerunnerblues/296">Open in Web</a>
<br><div class="message-flags"> 🏷 link </div></div></div>]]></content:encoded>
<br><div class="message-flags"> 🏷 link </div></div>]]></content:encoded>
<guid isPermaLink="true">https://t.me/bladerunnerblues/296</guid>
<pubDate>Fri, 12 Jan 2024 16:52:43 +0000</pubDate>
</item>
@@ -153,13 +154,14 @@
<description>Экипаж! Менять мир непросто. Иногда нам нужна правильная музыка. Приказ по радиорубке - включаем с утра на всех палубах и заряжаемся. Нас ждет прыжок в созвездие Ориона. https://youtu.be/9N_AinKeT_g?si=SFAulfGSNuGmh9QU P.S. если сегодня будете где-то слышать этот трек - знайте, что его поставил ваш брат или сестра с этого корабля:) и улыбнитесь:) с пятницей!</description>
<content:encoded><![CDATA[<div class="message-body"><div class="post">
<div class="message-media">
</div>
<br>
Экипаж!<br><br>Менять мир непросто. Иногда нам нужна правильная музыка. Приказ по радиорубке - включаем с утра на всех палубах и заряжаемся. Нас ждет прыжок в созвездие Ориона. <br><br><a href="https://youtu.be/9N_AinKeT_g?si=SFAulfGSNuGmh9QU" target="_blank">https://youtu.be/9N_AinKeT_g?si=SFAulfGSNuGmh9QU</a><br><br>P.S. если сегодня будете где-то слышать этот трек - знайте, что его поставил ваш брат или сестра с этого корабля:) и улыбнитесь:) <br>с пятницей!
<br>
</div><br></div>
<div class="message-footer"><br>
<span class="reaction">👍 1208&nbsp;&nbsp;</span><span class="reaction">❤ 447&nbsp;&nbsp;</span><span class="reaction">🔥 255&nbsp;&nbsp;</span><span class="reaction">❤‍🔥 55&nbsp;&nbsp;</span><span class="reaction">🫡 49&nbsp;&nbsp;</span><span class="reaction">😁 37&nbsp;&nbsp;</span><span class="reaction">🤔 9&nbsp;&nbsp;</span><span class="reaction">🤷‍♂ 6&nbsp;&nbsp;</span><span class="reaction">🗿 5&nbsp;&nbsp;</span><span class="reaction">🤡 4&nbsp;&nbsp;</span><span class="reaction">👾 4&nbsp;&nbsp;</span>&nbsp;&nbsp;|&nbsp;&nbsp;<span class="views">110203 👁</span>&nbsp;&nbsp;|&nbsp;&nbsp;<span class="date">16/02/24, 05:23:23</span>&nbsp;&nbsp;|&nbsp;&nbsp;<span class="message-id">#304</span><br><a href="tg://resolve?domain=bladerunnerblues&amp;post=304">Open in Telegram</a>&nbsp;|&nbsp;<a href="https://t.me/bladerunnerblues/304">Open in Web</a>
<br><div class="message-flags"> 🏷 link </div></div></div>]]></content:encoded>
<br><div class="message-flags"> 🏷 link </div></div>]]></content:encoded>
<guid isPermaLink="true">https://t.me/bladerunnerblues/304</guid>
<pubDate>Fri, 16 Feb 2024 05:23:23 +0000</pubDate>
</item>
@@ -169,13 +171,14 @@
<description>[ХОРОШИЕ НОВОСТИ ОБ ИННОВАЦИЯХ НА НЕСКОЛЬКО МИЛЛИАРДОВ ЗА ГОД И ДЕТЯХ, РОЖДЕННЫХ В СССР] Дорогой экипаж! Вдохновения и мотивации пост. Не собирался писать именно это и так эмоционально, но потом перечитал и решил, что не буду редактировать. И, даже если кто-то отпишется, – я никого не держу. Просто в это турбулентное время, хочется продолжать дарить вам надежду в лучшее, а не поощрять самоуничижение, как это делают многие. Хочу констатировать факты: не все уехали, не все плохо, нет, мы умеем делать сильные инженерные рывки в России (а не только в ВПК), нам есть, чем гордится и да, я считаю, что мы единый народ. Хочу, чтобы кому-то этот пост помог улыбнуться и ступать легко и уверенно. https://blog.cheresh.me/2024/02/20/billions-in-innovations-and-ussr/ P.S. Репосты приветствуются. А вот воровать не надо. Кто ворует мои посты - вы выглядите не очень умно:) Вы думаете, люди не видят, что ли?:) Карма is a bitch.</description>
<content:encoded><![CDATA[<div class="message-body"><div class="post">
<div class="message-media">
</div>
<br>
<b>[ХОРОШИЕ НОВОСТИ ОБ ИННОВАЦИЯХ НА НЕСКОЛЬКО МИЛЛИАРДОВ ЗА ГОД И ДЕТЯХ, РОЖДЕННЫХ В СССР]</b><br><br>Дорогой экипаж!<br><br>Вдохновения и мотивации пост.<br>Не собирался писать именно это и так эмоционально, но потом перечитал и решил, что не буду редактировать.<br>И, даже если кто-то отпишется, – я никого не держу. Просто в это турбулентное время, хочется продолжать дарить вам надежду в лучшее, а не поощрять самоуничижение, как это делают многие.<br> <br>Хочу констатировать факты: не все уехали, не все плохо, нет, мы умеем делать сильные инженерные рывки в России (а не только в ВПК), нам есть, чем гордится и да, я считаю, что мы единый народ. <br>Хочу, чтобы кому-то этот пост помог улыбнуться и ступать легко и уверенно. <br><br><a href="https://blog.cheresh.me/2024/02/20/billions-in-innovations-and-ussr/" target="_blank">https://blog.cheresh.me/2024/02/20/billions-in-innovations-and-ussr/</a><br><br>P.S. Репосты приветствуются. А вот воровать не надо. Кто ворует мои посты - вы выглядите не очень умно:) Вы думаете, люди не видят, что ли?:) Карма is a bitch.
<br>
</div><br></div>
<div class="message-footer"><br>
<span class="reaction">👍 2200&nbsp;&nbsp;</span><span class="reaction">❤ 916&nbsp;&nbsp;</span><span class="reaction">🔥 408&nbsp;&nbsp;</span><span class="reaction">🍾 70&nbsp;&nbsp;</span><span class="reaction">⚡ 23&nbsp;&nbsp;</span><span class="reaction">🤣 16&nbsp;&nbsp;</span><span class="reaction">🥰 12&nbsp;&nbsp;</span><span class="reaction">👌 11&nbsp;&nbsp;</span><span class="reaction">👎 10&nbsp;&nbsp;</span><span class="reaction">👻 5&nbsp;&nbsp;</span><span class="reaction">🥱 3&nbsp;&nbsp;</span>&nbsp;&nbsp;|&nbsp;&nbsp;<span class="views">690677 👁</span>&nbsp;&nbsp;|&nbsp;&nbsp;<span class="date">20/02/24, 10:10:22</span>&nbsp;&nbsp;|&nbsp;&nbsp;<span class="message-id">#305</span><br><a href="tg://resolve?domain=bladerunnerblues&amp;post=305">Open in Telegram</a>&nbsp;|&nbsp;<a href="https://t.me/bladerunnerblues/305">Open in Web</a>
<br><div class="message-flags"> 🏷 link </div></div></div>]]></content:encoded>
<br><div class="message-flags"> 🏷 link </div></div>]]></content:encoded>
<guid isPermaLink="true">https://t.me/bladerunnerblues/305</guid>
<pubDate>Tue, 20 Feb 2024 10:10:22 +0000</pubDate>
</item>
@@ -185,13 +188,14 @@
<description>Я тут одним днем был в Екатеринбурге. На конференции по кибербезопасности. На уральском ТВ записали короткое интервью. Не для экспертов, для обычных жителей планеты Земля - что такое кибербез простыми словами, какие угрозы сейчас и что делать - быть может кому-то будет полезно. *** по каким-то мистическим причинам, не всегда с мобилы проигрывается, с десктопа - точно работает. Не знаю, почему. p.s. На Мэта Деймона времени не хватило (с) :)) https://www.obltv.ru/broadcasting/programs/479443-sobytija_akcent/releases/4840574-evgeniy-chereshnev-seychas-khakery-eto-ne-studenty-idealisty-a-organizovannye-nayemniki/</description>
<content:encoded><![CDATA[<div class="message-body"><div class="post">
<div class="message-media">
</div>
<br>
Я тут одним днем был в Екатеринбурге. На конференции по кибербезопасности. На уральском ТВ записали короткое интервью. Не для экспертов, для обычных жителей планеты Земля - что такое кибербез простыми словами, какие угрозы сейчас и что делать - быть может кому-то будет полезно. <br><br>*** по каким-то мистическим причинам, не всегда с мобилы проигрывается, с десктопа - точно работает. Не знаю, почему. <br><br>p.s. На Мэта Деймона времени не хватило (с) :))<br><br><a href="https://www.obltv.ru/broadcasting/programs/479443-sobytija_akcent/releases/4840574-evgeniy-chereshnev-seychas-khakery-eto-ne-studenty-idealisty-a-organizovannye-nayemniki/" target="_blank">https://www.obltv.ru/broadcasting/programs/479443-sobytija_akcent/releases/4840574-evgeniy-chereshnev-seychas-khakery-eto-ne-studenty-idealisty-a-organizovannye-nayemniki/</a>
<br>
</div><br></div>
<div class="message-footer"><br>
<span class="reaction">👍 867&nbsp;&nbsp;</span><span class="reaction">❤ 233&nbsp;&nbsp;</span><span class="reaction">🔥 51&nbsp;&nbsp;</span><span class="reaction">👏 42&nbsp;&nbsp;</span><span class="reaction">🦄 10&nbsp;&nbsp;</span><span class="reaction">🎉 5&nbsp;&nbsp;</span><span class="reaction">💩 4&nbsp;&nbsp;</span><span class="reaction">🥰 3&nbsp;&nbsp;</span><span class="reaction">😁 3&nbsp;&nbsp;</span><span class="reaction">🌚 2&nbsp;&nbsp;</span>&nbsp;&nbsp;|&nbsp;&nbsp;<span class="views">121878 👁</span>&nbsp;&nbsp;|&nbsp;&nbsp;<span class="date">20/02/24, 14:01:23</span>&nbsp;&nbsp;|&nbsp;&nbsp;<span class="message-id">#306</span><br><a href="tg://resolve?domain=bladerunnerblues&amp;post=306">Open in Telegram</a>&nbsp;|&nbsp;<a href="https://t.me/bladerunnerblues/306">Open in Web</a>
<br><div class="message-flags"> 🏷 link </div></div></div>]]></content:encoded>
<br><div class="message-flags"> 🏷 link </div></div>]]></content:encoded>
<guid isPermaLink="true">https://t.me/bladerunnerblues/306</guid>
<pubDate>Tue, 20 Feb 2024 14:01:23 +0000</pubDate>
</item>
+2 -1
View File
@@ -1014,6 +1014,7 @@ The SM9 module boasts <b>hardware compatibility</b> with NVIDIA Jetson series mo
<div class="message-forward">--- Forwarded from асоциальный пикотранзистор ᶘಠᴥಠᶅ ---</div>
<br>
<div class="message-media">
</div>
<br>
Парсинг через описание структуры мне сразу напомнил про <a href="https://kaitai.io/," target="_blank">https://kaitai.io/,</a> но кажется проект больше мёртв, чем жив.
<br>
@@ -1021,7 +1022,7 @@ The SM9 module boasts <b>hardware compatibility</b> with NVIDIA Jetson series mo
</div><br></div>
<div class="message-footer"><br>
<span class="reaction">✍ 6&nbsp;&nbsp;</span><span class="reaction">👍 2&nbsp;&nbsp;</span><span class="reaction">❤ 1&nbsp;&nbsp;</span><span class="reaction">💊 1&nbsp;&nbsp;</span>&nbsp;&nbsp;|&nbsp;&nbsp;<span class="views">4876 👁</span>&nbsp;&nbsp;|&nbsp;&nbsp;<span class="date">13/03/25, 17:42:49</span>&nbsp;&nbsp;|&nbsp;&nbsp;<span class="message-id">#1347</span><br><a href="tg://resolve?domain=embedoka&amp;post=1347">Open in Telegram</a>&nbsp;|&nbsp;<a href="https://t.me/embedoka/1347">Open in Web</a>
<br><div class="message-flags"> 🏷 fwd 🏷 link </div></div></div>
<br><div class="message-flags"> 🏷 fwd 🏷 link </div></div>
<hr class="post-divider">
<div class="message-body"><div class="post">
<div class="message-forward">--- Forwarded from <a href="https://t.me/kitnerlive">kitnerlive (@kitnerlive)</a> ---</div>
+2 -1
View File
@@ -168,6 +168,7 @@
<div class="message-forward">--- Forwarded from асоциальный пикотранзистор ᶘಠᴥಠᶅ ---</div>
<br>
<div class="message-media">
</div>
<br>
Парсинг через описание структуры мне сразу напомнил про <a href="https://kaitai.io/," target="_blank">https://kaitai.io/,</a> но кажется проект больше мёртв, чем жив.
<br>
@@ -175,7 +176,7 @@
</div><br></div>
<div class="message-footer"><br>
<span class="reaction">✍ 6&nbsp;&nbsp;</span><span class="reaction">👍 2&nbsp;&nbsp;</span><span class="reaction">❤ 1&nbsp;&nbsp;</span><span class="reaction">💊 1&nbsp;&nbsp;</span>&nbsp;&nbsp;|&nbsp;&nbsp;<span class="views">4876 👁</span>&nbsp;&nbsp;|&nbsp;&nbsp;<span class="date">13/03/25, 17:42:49</span>&nbsp;&nbsp;|&nbsp;&nbsp;<span class="message-id">#1347</span><br><a href="tg://resolve?domain=embedoka&amp;post=1347">Open in Telegram</a>&nbsp;|&nbsp;<a href="https://t.me/embedoka/1347">Open in Web</a>
<br><div class="message-flags"> 🏷 fwd 🏷 link </div></div></div>]]></content:encoded>
<br><div class="message-flags"> 🏷 fwd 🏷 link </div></div>]]></content:encoded>
<guid isPermaLink="true">https://t.me/embedoka/1347</guid>
<pubDate>Thu, 13 Mar 2025 17:42:49 +0000</pubDate>
</item>
+2 -1
View File
@@ -609,6 +609,7 @@
<hr class="post-divider">
<div class="message-body"><div class="post">
<div class="message-media">
</div>
<br>
Илья Бирман в последнем выпуске своего подкаста вместе с Мишей Нозиком обсудили исследование, которое я проводил для внедрения изменений в шрифт Карт (<a href="https://t.me/meow_design/2090)." target="_blank">https://t.me/meow_design/2090).</a> <br><br>Фрагмент начинается с 56:45.
<br>
@@ -623,7 +624,7 @@
</div><br></div>
<div class="message-footer"><br>
<span class="views">1187 👁</span>&nbsp;&nbsp;|&nbsp;&nbsp;<span class="date">22/12/25, 15:22:09</span>&nbsp;&nbsp;|&nbsp;&nbsp;<span class="message-id">#2183</span><br><a href="tg://resolve?domain=meow_design&amp;post=2183">Open in Telegram</a>&nbsp;|&nbsp;<a href="https://t.me/meow_design/2183">Open in Web</a>
<br><div class="message-flags"> 🏷 fwd 🏷 no_image 🏷 link 🏷 mention 🏷 foreign_channel 🏷 merged </div></div></div>
<br><div class="message-flags"> 🏷 fwd 🏷 no_image 🏷 link 🏷 mention 🏷 foreign_channel 🏷 merged </div></div>
<hr class="post-divider">
<div class="message-body"><div class="post">
<div class="message-media">
+2 -1
View File
@@ -311,6 +311,7 @@
<description>Илья Бирман в последнем выпуске своего подкаста вместе с Мишей Нозиком обсудили исследование, которое я проводил для внедрения изменений в шрифт Карт (https://t.me/meow_design/2090). Фрагмент начинается с 56:45. Думаем дальше № 51 — «Три варианта апокалипсиса» c Мишей Нозиком С Мишей Нозиком обсуждаем хороший дизайн, хороший маркетинг, хорошее исследование (!) и пару вопросов по нейросетям. 0:00 — Миша оказался против горизонтальной прокрутки на мобиле 7:06 — Обсуждение: аналогия с теоремой о попапах, когда подойдёт, топ дизайнерских костылей 20:20 — Критерий хорошего дизайна 27:43 — Разбираем на примере полководцев, учителя русского языка, авиакомпании и чего-то ещё. Репутация и долгосрочное планирование 45:29 — Про маркетинг в бюро 52:41 — «Пипл хавает» против «дизайна для дизайнеров» 56:45 — Яндекс исследовал размер строчных букв в шрифте на картах 1:03:01 — ЧатГПТ и непонятная кнопка «Скачать» 1:13:26 — Как нейросеть решила убить человека Эпл · Ютюб · Я.Музыка · Мейв Но лучше подписаться по РСС в подкастном приложении: https://cloud.mave.digital/51724</description>
<content:encoded><![CDATA[<div class="message-body"><div class="post">
<div class="message-media">
</div>
<br>
Илья Бирман в последнем выпуске своего подкаста вместе с Мишей Нозиком обсудили исследование, которое я проводил для внедрения изменений в шрифт Карт (<a href="https://t.me/meow_design/2090)." target="_blank">https://t.me/meow_design/2090).</a> <br><br>Фрагмент начинается с 56:45.
<br>
@@ -325,7 +326,7 @@
</div><br></div>
<div class="message-footer"><br>
<span class="views">1187 👁</span>&nbsp;&nbsp;|&nbsp;&nbsp;<span class="date">22/12/25, 15:22:09</span>&nbsp;&nbsp;|&nbsp;&nbsp;<span class="message-id">#2183</span><br><a href="tg://resolve?domain=meow_design&amp;post=2183">Open in Telegram</a>&nbsp;|&nbsp;<a href="https://t.me/meow_design/2183">Open in Web</a>
<br><div class="message-flags"> 🏷 fwd 🏷 no_image 🏷 link 🏷 mention 🏷 foreign_channel 🏷 merged </div></div></div>]]></content:encoded>
<br><div class="message-flags"> 🏷 fwd 🏷 no_image 🏷 link 🏷 mention 🏷 foreign_channel 🏷 merged </div></div>]]></content:encoded>
<guid isPermaLink="true">https://t.me/meow_design/2183</guid>
<pubDate>Mon, 22 Dec 2025 15:22:09 +0000</pubDate>
</item>
+2 -2
View File
@@ -65,7 +65,7 @@
},
"file_unique_id_none": {
"collected": [],
"html": "<div class=\"message-media\">"
"html": "<div class=\"message-media\">\n</div>"
},
"live_photo": {
"collected": [
@@ -213,6 +213,6 @@
},
"webpage_without_photo": {
"collected": [],
"html": "<div class=\"message-media\">\n<div class=\"webpage-preview\">\n<div class=\"webpage-preview\" style=\"border-left: 3px solid #ccc; padding-left: 10px; margin: 10px 0;\">\n<div class=\"webpage-title\" style=\"font-weight:bold; margin:5px 0;\">\n<a href=\"https://example.com\" target=\"_blank\">Example</a></div>\n<div class=\"webpage-url\" style=\"color:#666; font-size:0.9em;margin-bottom:5px;\">https://example.com</div>\n</div>\n</div>"
"html": "<div class=\"message-media\">\n</div>\n<div class=\"webpage-preview\">\n<div class=\"webpage-preview\" style=\"border-left: 3px solid #ccc; padding-left: 10px; margin: 10px 0;\">\n<div class=\"webpage-title\" style=\"font-weight:bold; margin:5px 0;\">\n<a href=\"https://example.com\" target=\"_blank\">Example</a></div>\n<div class=\"webpage-url\" style=\"color:#666; font-size:0.9em;margin-bottom:5px;\">https://example.com</div>\n</div>\n</div>"
}
}
+137
View File
@@ -0,0 +1,137 @@
# flake8: noqa
# pylint: disable=protected-access, missing-function-docstring, redefined-outer-name, line-too-long
"""Stage-5b registered media fixes (render-pipeline refactor epic, issue #32/#34).
Two registry items, both routed through the single MEDIA_SOURCES table:
* §3.13 — the ">100MB don't cache" rule now applies to ANY selected media object,
not just message.video (previously only video, plus live_photo/story/poll).
* §3.14 — the <div class="message-media"> container is CLOSED in every branch;
a None file_unique_id used to leave it open (html5lib then swallowed following
posts / webpage previews into it).
The fragment snapshot (tests/test_data/media_fragments.json) was regenerated in the 5b
changeset: exactly two cases moved — `file_unique_id_none` and `webpage_without_photo`
each gained the now-balanced `</div>` (see test_stage5_media_table for the oracle).
The feed goldens moved only by the same `</div>` relocation on webpage-without-photo posts.
"""
from types import SimpleNamespace
import pytest
from pyrogram.enums import MessageMediaType
from post_parser import PostParser
from url_signer import KeyManager
from tests import media_fragment_replay as fr
@pytest.fixture(autouse=True)
def _pin_signing_key(monkeypatch):
monkeypatch.setattr(KeyManager, "signing_key", fr.FRAGMENT_SIGNING_KEY)
@pytest.fixture
def parser():
return PostParser(SimpleNamespace())
def _msg(mid, media, **extra):
return fr._msg(mid, media, **extra)
# --------------------------------------------------------------------------- #
# §3.14 — the message-media div is closed in every branch.
# --------------------------------------------------------------------------- #
def test_none_file_unique_id_closes_media_div(parser):
# A media type whose object has no usable file_unique_id: the container used to
# be left open. Now it must be closed.
msg = _msg(1, MessageMediaType.PHOTO, photo=SimpleNamespace(file_unique_id=None, file_id="x"))
html = parser._generate_html_media(msg)
assert html == '<div class="message-media">\n</div>'
def test_webpage_without_photo_closes_media_div_before_preview(parser):
# WEB_PAGE without photo: the empty media div must close BEFORE the webpage-preview
# block (previously the open div swallowed the preview and, at feed level, following
# posts). Every <div class="message-media"> is now paired with a </div>.
msg = _msg(2, MessageMediaType.WEB_PAGE, text="hi",
web_page=SimpleNamespace(photo=None, url="https://e.com", title="E",
description=None, site_name=None, type="", display_url=None))
html = parser._generate_html_media(msg)
assert html.startswith('<div class="message-media">\n</div>\n<div class="webpage-preview">')
assert html.count('<div class="message-media">') == 1
# The media container is now empty and closed, not wrapping the preview.
assert '<div class="message-media">\n</div>' in html
def test_channel_username_missing_still_closes_div(parser):
# The username-guard branch also closes the div (unchanged behavior, asserted so a
# future refactor cannot regress it).
msg = _msg(3, MessageMediaType.PHOTO, username=None, chat_id=555,
photo=SimpleNamespace(file_unique_id="u", file_id="f"))
html = parser._generate_html_media(msg)
assert html == '<div class="message-media">\n</div>'
@pytest.mark.parametrize("case_name", ["file_unique_id_none", "webpage_without_photo"])
def test_5b_fragment_cases_are_now_balanced(parser, case_name):
"""The two fragments that 5b intentionally changed must have a balanced media div."""
factory = fr.build_cases()[case_name]
html = parser._generate_html_media(factory())
assert html.count('<div class="message-media">') == 1
# There is at least one closing tag for the media container now.
assert '</div>' in html
# --------------------------------------------------------------------------- #
# §3.13 — the >100MB guard applies to ANY selected object, not only video.
# --------------------------------------------------------------------------- #
BIG = 200 * 1024 * 1024
SMALL = 5 * 1024 * 1024
@pytest.mark.parametrize("media_type,attr", [
(MessageMediaType.PHOTO, "photo"),
(MessageMediaType.DOCUMENT, "document"),
(MessageMediaType.AUDIO, "audio"),
(MessageMediaType.ANIMATION, "animation"),
])
def test_large_non_video_object_not_collected(parser, media_type, attr):
"""§3.13: a >100MB photo/document/audio/animation is no longer collected for the
download cache (before 5b only large VIDEO objects were skipped)."""
obj = SimpleNamespace(file_unique_id="big", file_id="f", file_size=BIG, mime_type="image/png")
msg = _msg(10, media_type, **{attr: obj})
parser._pending_media_ids = []
parser._save_media_file_ids(msg)
assert parser._pending_media_ids == []
@pytest.mark.parametrize("media_type,attr", [
(MessageMediaType.PHOTO, "photo"),
(MessageMediaType.DOCUMENT, "document"),
(MessageMediaType.AUDIO, "audio"),
])
def test_small_non_video_object_still_collected(parser, media_type, attr):
obj = SimpleNamespace(file_unique_id="small", file_id="f", file_size=SMALL, mime_type="image/png")
msg = _msg(11, media_type, **{attr: obj})
parser._pending_media_ids = []
parser._save_media_file_ids(msg)
assert [(c, p, f) for c, p, f, _ in parser._pending_media_ids] == [("testchan", 11, "small")]
def test_large_video_still_not_collected(parser):
# Regression: the video case (the only one guarded before 5b) still works.
msg = _msg(12, MessageMediaType.VIDEO,
video=SimpleNamespace(file_unique_id="v", file_id="f", file_size=BIG))
parser._pending_media_ids = []
parser._save_media_file_ids(msg)
assert parser._pending_media_ids == []
def test_object_without_file_size_is_collected(parser):
# No file_size attribute -> not guarded (the common case for photos).
msg = _msg(13, MessageMediaType.PHOTO, photo=SimpleNamespace(file_unique_id="nofs", file_id="f"))
parser._pending_media_ids = []
parser._save_media_file_ids(msg)
assert [(c, p, f) for c, p, f, _ in parser._pending_media_ids] == [("testchan", 13, "nofs")]