# tubev — Ads Integration Реклама через **adspyglass.com**. Основне джерело монетизації — балансуємо CTR vs UX/PSI. ## Status 🟢 **Working knowledge** — Skeleton наповнюємо. ## Architecture ### Mirrors (зеркала) Реклама вантажиться через **зеркала-домени**, не прямо `adspyglass.com`: - `a5.g--o.info` — ad orchestration (preconnect target у modern setup) - `surstrom.com` — inline ad-spot loader (legacy pattern) - `agego.com` — verifycdn (`verifycdn.agego.com/v1/verify.js`) - `g--o.info` — base domain - (інші додаються на потребу) **Чому зеркала:** anti-block — adblockers баняють відомі ad-домени. Зеркала маскують та ротуються. **Mirror lifecycle:** - Зеркала **періодично баняться** (adblock list updates) - Заміна — **mass-operation через Адміна** (одразу на всі сайти) - Ми не керуємо вибором зеркал — це адмінська функція ### Three architecture patterns coexist (audit 2026-05-02) Site-level audit показав **3 patterns** — не uniform: | Pattern | Sites | Як виглядає | Примітка | |---------|-------|-------------|----------| | **A) Modern bundle** | 1 (тільки 8148) | ` ... <% render("views.modules.banners.header_mobile_adspy") %> <% render("views.modules.banners.footer_mobile_adspy") %> <% render("views.modules.banners.footer_descktop_adspy") %> ``` **Pattern C (8112 legacy inline):** ```etlua ... ... tb.load_frame_baner_v2("//surstrom.com/api/spots/72437?p=1","#tb0",{...},{...}); ``` ## Що треба з'ясувати + задокументувати ### Architecture migration - [ ] Чи планується мігрувати pattern C → B/A (legacy → modern)? - [ ] 8148 — pilot для bundle-architecture, чи поширюватиметься? ### CSP / Security - [ ] CSP exceptions для зеркал — як підтримуються? - [ ] Mirror swap — чи треба update CSP при заміні? ### Performance impact - [ ] PSI вплив реклами — % LCP / TBT (per pattern)? - [ ] Lazy-load ads below-fold — реалізовано (видно `loading="lazy"` на iframes)? ## VAST flow (8148 detailed) ### User experience 1. Користувач клацає play на `pjs_play_btn` (PlayerJS player) 2. `asgInVideoImpression` event від ASG SDK → `_decideAndApply` ловить → запускає `VastPreroll.show()` 3. ASG іnject-ить `.asg-container` з video preroll 4. `MutationObserver` ловить container → pin pointer + z-index 5000, добавляє progress bar (`.vast-progress` yellow #ffd000) 5. Coordinated mute: video у container синхронізується з `_vastMuted` localStorage (per-tab persist) 6. Після VAST done (video.ended OR `currentTime >= duration - 0.2`) → callback `window._asgAdDone()` → main video starts via `window._revealPjs()` 7. `enableMediaPlayHijack: true` блокує race у HTMLMediaElement.play() якщо `_adsLocked` — попереджає 1-frame audio artifact коли VAST стартує над main video ### Cooldown management - ASG локальне сховище: `localStorage.asgsl` — pipe-separated `=:` записи. Ключ `global_rr` = "remaining ratio" (timestamp до якого spot у cooldown). - Дублюючі cookies: `_popRr`, `_vastRr`. Реплікуються з asgsl при impression event. - Декрипт пам'яті: дві ключові події з ASG — `asgPopunderImpression`, `asgInVideoImpression` — тригерять запис cooldown. ### Mode decision (`AdCore._decide`) - `popActive = true && vastActive = true` → `none` (поки активна `recoverFromNone`) - `popActive = false` → `pop` (priority) - `popActive = true && vastActive = false` → `vast` - AND `vastPolicy "show-1-skip-1"` skip pattern на половину VAST imps ### Policy choice `pop-priority` policy + `show-1-skip-1` для VAST — **навмисний баланс ревеню vs UX**: - Popunder показується відносно рідко (cap від ASG високий) - VAST спрацьовує часто, тому штучно скачуємо до 50% (`show-1-skip-1`) — менше тиску на юзера, не вбиває engagement - Якщо колись треба максимізувати ревеню → `vastPolicy: 'show-always'` ## Open questions for developer 1. Як здійснюється mirror swap — sed-replace у всіх template/JS файлах через Адміна, runtime config, чи інший механізм? 2. Які pattern використовується для НЕ-77 сайтів (17 без adspy banner modules) — special-case structure, "no ads" сайти, чи щось інше? 3. SDK URLs (`nDNVal3.js`, `9iO21Eb.js`) — чи стабільні чи можуть змінитися при mirror rotation?