6.9 KiB
Баннеры (informer) в web-версии MAX
Баннеры вроде «Публичные каналы — для всех» внутри кода называются informer.
Они полностью приходят с сервера по WebSocket запросом с опкодом 302.
В JS-бандлах текста баннеров нет — локально хранятся только счётчики показов.
Исходники: dump/web.max.ru/_app/immutable/chunks/BWjA24QQ.js (логика),
_app/immutable/nodes/9.Dqm5zlvE.js (рендер тайла + аналитика).
Как это работает
- В общем sync-ответе сессии сервер выставляет бит
1в bitmask-полеupdates:e.updates && new Pu(e.updates).get(1) && await J.banners.resync() - Клиент шлёт запрос с опкодом 302:
Ah = Y(async ({bannersSync:e}, {send:t}) => await t(302, {bannersSync:e})) // resync(): let e = await Ah({bannersSync:0}); await this.upsert(e); - Сервер отвечает
{showTime, updateTime, banners:[…]}. - Какой баннер показать — считается на клиенте (
activeBanner): фильтрcanShow, затем выбор с максимальнымpriority. - Весь механизм гейтится серверным конфигом
informer-enabled. - Состояние показов хранится в
localStorage['__oneme_informer']:informerState = { lastShowedBannerId: null, banners: { /* id -> {showCounter, closedTime} */ } }
Пример ответа сервера
{
"ver": 10,
"cmd": 1,
"seq": 14,
"opcode": 302,
"payload": {
"showTime": 86400000,
"updateTime": 1784123975588,
"banners": [
{
"id": "public_channels_cid_test",
"title": "Публичные каналы — для всех",
"settings": 1,
"description": "Привлекайте новую аудиторию",
"priority": 16,
"repeat": 1,
"rerun": 5400000000000000,
"animojiId": 1446,
"url": "https://max.ru/max_news/AZ9kk1KhJAo",
"type": 1
}
]
}
}
Конверт (обёртка WS-сообщения)
| Поле | Значение | На что влияет |
|---|---|---|
ver |
10 | Версия протокола WebSocket. |
cmd |
1 | Тип пакета. 1 = ответ на запрос (response), не server-push. |
seq |
14 | Номер запроса. Клиент послал 302 {bannersSync:0} под этим seq — сервер отвечает тем же seq для матчинга. |
opcode |
302 | Код операции = синхронизация баннеров/informer. |
payload |
{…} | Полезная нагрузка, попадает в banners.upsert(e). |
payload — верхний уровень
showTime: 86400000 (24 ч в мс)
Сколько времени баннер считается «свежим» после первого показа.
isShowTimeOver = ka.now - this.showAt > this.showTime
Прошло больше showTime с момента первого показа → canShow = false, баннер пропадает.
updateTime: 1784123975588 (unix-мс)
Версия набора баннеров. Новые данные применяются только если пришло свежее:
e.banners && e.updateTime > this.informer.updateTime && (…apply…)
Объект баннера
id: "public_channels_cid_test"
Уникальный ключ. По нему хранятся showCounter и closedTime в localStorage['__oneme_informer']
и запоминается lastShowedBannerId (чтобы не показать один баннер подряд дважды).
Суффикс _test = тестовый баннер.
title: «Публичные каналы — для всех» — верхняя (цветная) строка тайла.
description: «Привлекайте новую аудиторию» — вторая строка. Оба текста только с сервера.
settings: 1 — битовая маска флагов отображения (new Pu(settings)). Биты:
1= TEXT_ANIMATION — анимация текста2= HIDE_CLOSE_BUTTON — скрыть крестик4= HIDE_ON_CLICK — закрывать по клику8= ICON_THEME_COLOR — красить иконку в цвет темы
Здесь 1 → только анимация текста; крестик «×» есть, клик ведёт по ссылке.
priority: 16
Приоритет при нескольких баннерах — показывается один с максимальным:
e.reduce((a,b) => b.priority > a.priority ? b : a)
При одном баннере роли не играет.
repeat: 1
Максимум показов:
hasRemainingShows = showCounter===0 ? true : showCounter < repeat
1 → показать ровно один раз.
rerun: 5400000000000000
Кулдаун (мс) перед повторным показом после закрытия крестиком:
isCloseCooldownOver = closedAt ? (rerun>0 ? Date.now()-closedAt > rerun : false) : true
Значение огромное (~171 000 лет) → «закрыл — больше не увидишь».
animojiId: 1446
ID аниможи-иконки слева в тайле:
J.assets.animojisCache.getLazy(bu.resolveId(this.$.animojiId))
url: https://max.ru/max_news/AZ9kk1KhJAo
Куда ведёт клик (вместе с type:1).
type: 1 — тип баннера:
0TYPE_TEXT — просто текст1TYPE_LINK — кликабельный, открываетurl← этот случай2TYPE_UPDATE — баннер обновления приложения
Итог по этому баннеру
Тестовый кликабельный баннер про публичные каналы: показывается один раз (repeat:1),
с анимацией текста (settings:1), «живёт» сутки после показа (showTime), по клику
открывает max.ru/max_news/...; если закрыть крестиком — не возвращается практически
никогда (rerun). Приоритет 16 нужен только при конкуренции нескольких баннеров.
Убрать/подменить баннер локально можно, перехватив ответ на опкод 302
либо отключив серверный флаг informer-enabled.