Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <div id="outstream_%SITE_AREA_ID%_%DIV_SUB_ID%" style="position: relative; width: 100%;"></div>
- <script type="text/javascript">
- (() => {
- const CONFIG = {
- containerId: 'outstream_%SITE_AREA_ID%_%DIV_SUB_ID%',
- siteId: 221350,
- baseBanner: { blockId: 723779, viewTimeMs: 2500 },
- fallbackBanner: { blockId: 723777 },
- videoDemand: {
- network: 'vk',
- placementId: '2014812',
- timeoutMs: 5000
- }
- };
- const mainContainer = document.getElementById(CONFIG.containerId);
- if (!mainContainer) return;
- const isDebug = /[?&]outstream_debug=1/.test(window.location.search);
- const logger = (...args) => {
- if (isDebug) console.log(`[Waterfall | ${CONFIG.containerId}] ->`, ...args);
- };
- mainContainer.style.position = 'relative';
- const layerVideo = document.createElement('div');
- layerVideo.style.cssText = 'position: relative; width: 100%; min-height: 0px; z-index: 1;';
- mainContainer.appendChild(layerVideo);
- const layerBase = document.createElement('div');
- layerBase.style.cssText = 'position: relative; width: 100%; z-index: 10000; background: #fff; transition: opacity 0.3s;';
- layerVideo.appendChild(layerBase);
- const demandWrapper = document.createElement('div');
- demandWrapper.style.cssText = 'position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; opacity: 0;';
- layerVideo.appendChild(demandWrapper);
- let state = {
- baseViewed: false, baseEmpty: false, demandStarted: false,
- videoReady: false, videoFailed: false, videoCompleted: false,
- videoShown: false, finalized: false
- };
- const loadLuxupBlock = (wrapperDiv, siteId, blockId) => {
- const divId = "lx_" + blockId + "_" + Math.floor(Math.random() * 10000);
- const el = document.createElement('div'); el.id = divId; wrapperDiv.appendChild(el);
- (window['__lxGc__'] = window['__lxGc__'] || {'s':{},'b':0})['cmd'] = window['__lxGc__']['cmd'] || [];
- window['__lxGc__']['cmd'].push(() => window['__lxGc__']['display'](divId, "_"+siteId, "_"+blockId));
- };
- const showFallback = (reason) => {
- if (state.finalized) return;
- state.finalized = true;
- mainContainer.innerHTML = '';
- logger("Заглушка. Причина: " + reason);
- const fallbackWrapper = document.createElement('div');
- mainContainer.appendChild(fallbackWrapper);
- // Используем единый siteId из CONFIG
- loadLuxupBlock(fallbackWrapper, CONFIG.siteId, CONFIG.fallbackBanner.blockId);
- };
- const checkFlow = () => {
- if (state.finalized) return;
- const baseDone = state.baseViewed || state.baseEmpty;
- if (baseDone) {
- if (!state.demandStarted) { startVideoDemand(); return; }
- if (state.videoCompleted) {
- showFallback('Видео завершило показ креатива');
- }
- else if (state.videoFailed) {
- logger('Видео недоступно. Оставляем первый баннер.');
- demandWrapper.style.display = 'none';
- layerBase.style.display = '';
- state.finalized = true;
- }
- else if (state.videoReady && !state.videoShown) {
- state.videoShown = true;
- logger('Показываем Video Demand');
- layerBase.style.display = 'none';
- demandWrapper.style.position = 'relative';
- demandWrapper.style.opacity = '1';
- demandWrapper.style.pointerEvents = 'auto';
- }
- }
- };
- const startVideoDemand = () => {
- if (state.demandStarted) return;
- state.demandStarted = true;
- Adapters[CONFIG.videoDemand.network](demandWrapper, CONFIG.videoDemand, {
- onReady: (msg) => { logger(msg); state.videoReady = true; checkFlow(); },
- onFail: (msg) => { logger(msg); state.videoFailed = true; checkFlow(); },
- onComplete: (msg) => { logger(msg); state.videoCompleted = true; checkFlow(); }
- });
- };
- const Adapters = {
- vk: (wrapper, config, callbacks) => {
- let isStarted = false;
- let isEnded = false;
- const currentSpot = config.placementId.toString();
- const vkDivId = 'adman-ads-' + currentSpot + '-' + Math.floor(Math.random() * 10000);
- const vkDiv = document.createElement('div');
- vkDiv.id = vkDivId;
- vkDiv.className = 'vk-adman-wrapper';
- vkDiv.style.cssText = 'display:inline-block;width:100%;height:100%;';
- wrapper.appendChild(vkDiv);
- const hideCloseButton = () => {
- const parentContainer = mainContainer.closest('[id^="lx_"]');
- if (parentContainer) {
- const style = document.createElement('style');
- style.innerHTML = `#${parentContainer.id} > .lx_close_button { display: none !important; }`;
- document.head.appendChild(style);
- logger(`Кнопка закрытия скрыта для блока #${parentContainer.id}`);
- }
- };
- const currentTimeoutMs = config.timeoutMs || 5000;
- const fallbackTimeout = setTimeout(() => {
- if (!isStarted && !isEnded) {
- isEnded = true;
- wrapper.innerHTML = '';
- callbacks.onFail(`VK: Таймаут ответа аукциона (${currentTimeoutMs / 1000} сек)`);
- }
- }, currentTimeoutMs);
- if (!window.AdManPlayer) {
- const func = function() { this.push(Array.prototype.slice.apply(arguments)); };
- window.AdManPlayer = func.bind(window._AdManPlayerInit = []);
- window.AdManSDK = func.bind(window._AdManSDKInit = []);
- }
- window.AdManPlayer({
- container: '#' + vkDivId,
- slot: currentSpot,
- onReady: () => {
- if (isEnded) return;
- if (!isStarted) {
- isStarted = true;
- clearTimeout(fallbackTimeout);
- callbacks.onReady('VK: Реклама готова (onReady)');
- }
- },
- onStarted: () => {
- if (isEnded) return;
- if (!isStarted) {
- isStarted = true;
- clearTimeout(fallbackTimeout);
- callbacks.onReady('VK: Реклама стартовала (onStarted)');
- }
- },
- onError: (err) => {
- if (isEnded) return;
- isEnded = true;
- clearTimeout(fallbackTimeout);
- wrapper.innerHTML = '';
- hideCloseButton();
- if (isStarted) {
- callbacks.onComplete('VK: Ошибка во время показа');
- } else {
- callbacks.onFail('VK: Нет рекламы (False Fill / Error)');
- }
- },
- onCompleted: () => {
- if (isEnded) return;
- isEnded = true;
- wrapper.innerHTML = '';
- hideCloseButton();
- callbacks.onComplete('VK: Видео завершено');
- },
- onSkipped: () => {
- if (isEnded) return;
- isEnded = true;
- wrapper.innerHTML = '';
- hideCloseButton();
- callbacks.onComplete('VK: Видео пропущено');
- },
- onClosed: () => {
- if (isEnded) return;
- isEnded = true;
- wrapper.innerHTML = '';
- hideCloseButton();
- callbacks.onComplete('VK: Блок закрыт');
- },
- onPlayed: () => logger(`VK: Воспроизведение`),
- onPaused: () => logger(`VK: Пауза`),
- onClicked: () => logger(`VK: Клик по рекламе`)
- });
- logger(`Загрузка vk-adman.js (Advanced Mode)...`);
- const s = document.createElement("script");
- s.src = 'https://ad.mail.ru/static/vk-adman.js';
- s.async = true;
- s.onerror = () => {
- if (!isEnded) {
- isEnded = true;
- clearTimeout(fallbackTimeout);
- wrapper.innerHTML = '';
- callbacks.onFail('Ошибка загрузки библиотеки VK');
- }
- };
- document.head.appendChild(s);
- }
- };
- logger('Старт Base Banner');
- // Использование единого siteId
- loadLuxupBlock(layerBase, CONFIG.siteId, CONFIG.baseBanner.blockId);
- const startViewabilityTracker = () => {
- let timeInView = 0;
- let isVisible = false;
- const requiredTime = CONFIG.baseBanner.viewTimeMs;
- const tickRate = 100;
- const io = new IntersectionObserver((entries) => {
- isVisible = entries[0].isIntersecting;
- }, { threshold: 0.1 });
- io.observe(mainContainer);
- const timer = setInterval(() => {
- if (isVisible && !document.hidden) {
- timeInView += tickRate;
- if (timeInView >= requiredTime) {
- clearInterval(timer);
- io.disconnect();
- logger(`Баннер просмотрен ${requiredTime}мс`);
- state.baseViewed = true;
- checkFlow();
- }
- }
- }, tickRate);
- };
- const checkBaseStatus = () => {
- if (state.finalized) return false;
- if (layerBase.querySelector('.__lxG__not_empty_block')) {
- logger('Баннер загружен, ждем попадания во вьюпорт');
- startViewabilityTracker();
- return true;
- }
- if (layerBase.querySelector('.__lxG__rendered_none')) {
- state.baseEmpty = true;
- checkFlow();
- return true;
- }
- return false;
- };
- const baseObserver = new MutationObserver(() => {
- if (checkBaseStatus()) {
- baseObserver.disconnect();
- }
- });
- baseObserver.observe(layerBase, {
- childList: true,
- subtree: true,
- attributes: true,
- attributeFilter: ['class']
- });
- if (checkBaseStatus()) {
- baseObserver.disconnect();
- }
- })();
- </script>
Advertisement
Add Comment
Please, Sign In to add comment