Regulace podle NIS2: Bojovat ve Sněmovně se bude hlavně o pravomoce NÚKIBu zakazovat dodavatele

1. 10. 2024
Doba čtení: 7 minut

Sdílet

Autor: Karel Choc, Internet Info
Bezpečnost dodavatelského řetězce označili operátoři za bolavé místo celého zákona. Opozici pak vadí i odbyté projednání v Legislativní radě vlády.

Hned tři výbory a jeden sněmovní podvýbor jednaly minulý týden o návrhu zákona o kybernetické bezpečnosti. Atmosféra na nich se lišila podle toho, z jakého úhlu pohledu se zákonodárci na navrženou regulaci dívali. Zatímco na výborech pro obranu a pro bezpečnost převažovaly hlasy volající po tom, že Česko normu potřebuje včetně kontroverzního mechanismu prověřování bezpečnosti dodavatelského řetězce, z Hospodářského výboru odcházeli zástupci Národního úřadu pro kybernetickou a informační bezpečnost (NÚKIB) s hlavou svěšenou. I koaliční poslanci totiž vůči návrhu nešetřili kritikou, a to nejen kvůli kvalitě materie samotné, ale i způsobu, jakým prošla Legislativní radou vlády (LRV).

Lupa všechny důležité hlasy, které na Výboru pro bezpečnost a Hospodářském výboru zazněly, zaznamenala, a v rámci seriálu věnovanému kybernetické bezpečnosti může dění ve Sněmovní ulici zprostředkovat. 

Nenechme stát bezbranný, žádal Řehka

Šéf NÚKIBu Lukáš Kintr na úvod projednání v bezpečnostním výboru zopakoval, že stát nemá ve stávajícím právním řádu žádný nástroj, kterým by byl schopen řešit strategickou závislost na dodavateli, a jeho nutnost ilustroval vývojem ruské invaze na Ukrajinu. Podotkl, že zbavit se dlouhodobě neřízené závislosti na ruském plynu a ropě je pořád jednodušší než vyměnit technologický celek. „Taková závislost v celé oblasti ICT existuje a my ji pozorujeme. Pro stát je z dlouhodobého hlediska nevýhodná a neakceptovatelná. Přestože tato rizika jsou dávno známa, v současnosti nemá stát efektivní rámec, jak je řešit,“ uvedl Kintr.

Náčelník generálního štábu a Kintrův předchůdce v čele úřadu Karel Řehka podpořil nutnost mít kvalitní regulaci kyberbezpečnosti několika příklady z nedávné doby. Zmínil kyberútoky na železnice v Polsku, kdy se v minulém roce hackerům podařilo vysíláním na určitých frekvencích aktivovat systém nouzového zastavení a vyřadit tak na několik hodin z provozu 20 vlaků. Připomenul také útok z roku 2017, který paralyzoval energetickou síť Ukrajiny, letošní případ CrowdStrike nebo útoky na lodní dopravu. Ty se jen v loňském roce dotkly více než tisícovky lodí.

„Chcete-li příklad, jak je nebezpečné, když si nehlídáte dodavatelský řetězec, stačí se zeptat Hizballáhu pár dní nazpátek,“ uvedl v narážce na vybuchující pagery a vysílačky Řehka a dodal: „Nemyslete si, že to neprobíhá i v České republice. Máme nějakou mlčenlivost, ale velcí hráči – a těch se to tady taky týkalo, to ne vždy zvládli se ctí.“

Odolnost civilní infrastruktury je podle něj naprosto zásadní i z obranného hlediska. Zmínil přitom regionální alianční plány, kdy ještě za mírového stavu je nutné při určitých varováních zabezpečit rychlé pohyby a přesuny a přijmout opatření, která odstraší nepřítele. „Funkčnost a rychlost může znamenat rozdíl mezi mírem a válkou, jestli se povede odstrašit protivníka, a pokud narušíte přepravu nebo energetickou síť, významně narušíte i proveditelnost tohoto plánu,“ varoval Řehka.

Zároveň vyjádřil obavu, aby stejně jako při každé podobné regulaci projednávané Sněmovnou nebyl návrh pod různými záminkami „vykosťován“, když už teď je podle něj na minimu, pod nějž už by postrádal smysl. „Dopadne to tak, že se to bude zdržovat, až se to vyzdržuje, spadne to a dalších několik let nebude mít tato země nástroje, jak se bránit. Jim to vyhovuje, že stát tyto nástroje nemá, a rádi by to tak nechali nastaveno. Za armádu bych apeloval, nenechme stát bezbranný,“ uzavřel svou promluvu Řehka.

Hostem bezpečnostního výboru byl i senátor Pavel Fischer, který má tuto problematiku na starosti v horní komoře. Podle něj nelze zapomínat na to, že Česko je členem NATO. „Je v pořádku, že chceme mít v zákoně víc, než je podle EU nezbytné. Zkomplikujeme si spolupráci se Spojenými státy v oblasti obrany a bezpečnosti – jen kvůli tomu, že ten zákon ještě nemáme,“ varoval.

Operátoři chtějí předvídatelnost

Poslanci dále odhlasovali, že na výboru může jako host vystoupit šéf Asociace provozovatelů mobilních sítí Jiří Grund. Podle něj je kybernetická bezpečnost pro telekomunikační sektor zásadní věc, aby vůbec mohly tyto služby fungovat.„Základní rozpor s předkladatelem je v síle opatření. My se domníváme, že je možné dosáhnout kyberbezpečnostních cílů pro náš stát s daleko nižšími náklady a chytřejším přístupem,“ řekl a přirovnal navržený instrument zákazu dodavatelů ke kanonu na vrabce, který nepřinese kýžený efekt. 

Čeští operátoři podle Grunda po varování NÚKIBu před Huawei a ZTE v roce 2018 sami přijali rozhodnutí, že do konce roku 2026 kritické systémy v jejich sítích nebudou mít žádné prvky čínské provenience. To sklidilo mezi přítomnými posměch, když osmiletá reakční doba není dostatečná.

„Největší problém, který my se zákonem máme, není to, že stát chce mít schopnost dodavatele zakázat, ale že je to pro nás nepředvídatelné,“ upozornil Grund, že zákon sice pracuje s daňovými odpisy, ale nerespektuje životní cyklus nakoupených investic. Tyto technologie tak lze používat v sítích i poté, co jsou v účetnictví daňově odepsány.

„Vymlčet to, shodit to dál, o to vám jde,“ reagoval Řehka na Gruntovo vystoupení a pokračoval: „Vzpomínám si, že jako ředitel NÚKIBu jsem jednal s šéfem operátorů a snažil se ho přesvědčit, že dřív nebo později ta doba přijde, že bude potřeba regulovat dodavatele. A on se mi vysmál, že nevěří tomu, že se toto opatření někdy prosadí.“

Opozice kritizovala fígl s legislativní radou

Proti tomu Hospodářský výbor byl vůči návrhu kyberbezpečnostního zákona ještě kritičtější. Jeho předseda, koaliční poslanec za ODS Ivan Adamec si několikrát nebral servítky. „Je to průšvih. Vy nevíte, kolik to bude stát. My řešíme, aby to bylo co nejlevnější a nejefektivnější,“ prohlásil směrem k zástupcům NÚKIBu.

Roman Kubíček z hnutí ANO následně použil paralelu se zaváděním GDPR. „Stejná panika, nakonec víme, jak to dopadlo. Ale kolik lidí se na tom přiživilo? Já mám strach, abychom se nedostali do módu, že na tom někdo dobře vydělá, ale skutek utek,“ vyjádřil své obavy.

Jeho spolustraník Marek Novák se zajímal o analýzu dopadů RIA. A ptal se zástupců NÚKIBu, zda úřad zkoušel udělat průzkum ve firmách, kterých se regulace dotkne, jak jsou s opatřeními pro lepší kyberbezpečnost daleko a jaké další náklady odhadují. Regulátor odvětil, že průzkumů vznikla celá řada, ale není jednotná metodika, která by dokázala odlišit běžné náklady na ICT od těch souvisejících s kyberbezpečností. „Data, která se vracejí, jsou natolik různorodá, že jakýkoliv závěr z nich vypovídací hodnotu nemá,“ uzavřel zástupce úřadu.

Jiří Grund tentokrát i bez hlasování o udělení slova zopakoval, že mechanismus bezpečnosti dodavatelského řetězce je bolavým místem celého návrhu, protože vytváří nepředvídatelnost podnikatelského prostředí. 

„Nedokážeme si představit, že za dva roky za námi přijde úředník, který řekne, že musíme nějaké technologie ze sítě vyhodit. Nás to děsí a právem. My chceme tu bezpečnost předvídatelnou. Chceme, aby bylo jasně stanoveno, kde začíná a končí regulace. Když něco vyhodíme z jádra, jestli to bude dostačující,“ prohlásil a zkritizoval snahu NÚKIBu o neomezené pravomoci. Za operátory označil hrozbu, že zákon bude fungovat jako bianco šek pro úřad a ten na základě vyhlášek bude rozhodovat, kde regulace začíná a kde končí.

Regulace podle NIS2: Mocenský apetit a odbytá RIA. Vládní právníci cupují kyberbezpečnostní zákon Přečtěte si také:

Regulace podle NIS2: Mocenský apetit a odbytá RIA. Vládní právníci cupují kyberbezpečnostní zákon

Stejně jako Grunt se i poslankyně za ANO Berenika Peštová dotkla způsobu, jakým návrh doputoval vlády. Připomeňme, že tomu předcházel nutný mezikrok, a to Legislativní rada vlády, která projednání zákona napoprvé přerušila a vrátila NÚKIBu k přepracování. Na její dotaz Lukáš Kintr potvrdil, že podruhé se už upravený zákon na plénum LRV nevrátil.

Peštová pak poznamenala, že tento scénář je u současné vládní koalice čím dál častější. „Na plénu vás roztrhají, vrátí to na úřad, a pak máte jít do komisí. Tam jsou ty největší právnické kapacity. A tam by vám řekli, jestli jste zapracovali připomínky správně, nebo ne. Kdybyste s tím šli zpátky na plénum, tak vás rozcupují korporátní právníci, že je to špatně a že nemáte vypořádané připomínky vznesené Hospodářskou komorou,“ poukázala Peštová na to, že návrh prošel pouze souhlasným stanoviskem předsedy LRV Michala Šalomouna.

CIF25_SE_terc

Prázdný zákon pro úředníky

Před závěrečným hlasováním o přerušení tohoto bodu předseda výboru Adamec směrem k NÚKIBu prohlásil: „Rozhodně vám to zadarmo nedáme. Zákon je naprosto prázdný a vše se dělá vyhláškami. Úředníci vítězí nad politiky. To fakt nechci.“

Nejkratší termín pro pozměňovací návrhy stanovil Výbor pro obranu. Očekává je do 25. října. Výbor pro bezpečnost a Hospodářský výbor přijímají návrhy na změnu o čtyři dny déle. Znovu se tak zákonem budou příslušné výbory zaobírat v listopadu. Je tak jasné, že se nestihne nejen transpoziční lhůta, která končí 17. října, ale reálná není ani posunutá představa regulátora, že by zákon mohl platit od začátku příštího roku.

  • Chcete mít Lupu bez bannerů?
  • Chcete dostávat speciální týdenní newsletter o zákulisí českého internetu?
  • Chcete mít k dispozici strojové přepisy podcastů?
  • Chcete získat slevu 1 000 Kč na jednu z našich konferencí?

Staňte se naším podporovatelem

Neutrální ikona do widgetu na odběr článků ze seriálů

Zajímá vás toto téma? Chcete se o něm dozvědět víc?

Objednejte si upozornění na nově vydané články do vašeho mailu. Žádný článek vám tak neuteče.


Autor článku

Redaktor serveru Lupa.cz se zaměřením na telekomunikace, média, IT a právo. Dříve šéfredaktor Právního rádce a mluvčí Českého telekomunikačního úřadu.

'; document.getElementById('preroll-iframe').onload = function () { setupIframe(); } prerollContainer = document.getElementsByClassName('preroll-container-iframe')[0]; } function setupIframe() { prerollDocument = document.getElementById('preroll-iframe').contentWindow.document; let el = prerollDocument.createElement('style'); prerollDocument.head.appendChild(el); el.innerText = "#adContainer>div:nth-of-type(1),#adContainer>div:nth-of-type(1) > iframe { width: 99% !important;height: 99% !important;max-width: 100%;}#videoContent,body{ width:100vw;height:100vh}body{ font-family:'Helvetica Neue',Arial,sans-serif}#videoContent{ overflow:hidden;background:#000}#adMuteBtn{ width:35px;height:35px;border:0;background:0 0;display:none;position:absolute;fill:rgba(230,230,230,1);bottom:20px;right:25px}"; videoContent = prerollDocument.getElementById('contentElement'); videoContent.style.display = 'none'; videoContent.volume = 1; videoContent.muted = false; const playPromise = videoContent.play(); if (playPromise !== undefined) { playPromise.then(function () { console.log('PREROLL sound allowed'); // setUpIMA(true); videoContent.volume = 1; videoContent.muted = false; setUpIMA(); }).catch(function () { console.log('PREROLL sound forbidden'); videoContent.volume = 0; videoContent.muted = true; setUpIMA(); }); } } function setupDimensions() { prerollWidth = Math.min(iinfoPrerollPosition.offsetWidth, 480); prerollHeight = Math.min(iinfoPrerollPosition.offsetHeight, 320); } function setUpIMA() { google.ima.settings.setDisableCustomPlaybackForIOS10Plus(true); google.ima.settings.setLocale('cs'); google.ima.settings.setNumRedirects(10); // Create the ad display container. createAdDisplayContainer(); // Create ads loader. adsLoader = new google.ima.AdsLoader(adDisplayContainer); // Listen and respond to ads loaded and error events. adsLoader.addEventListener( google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED, onAdsManagerLoaded, false); adsLoader.addEventListener( google.ima.AdErrorEvent.Type.AD_ERROR, onAdError, false); // An event listener to tell the SDK that our content video // is completed so the SDK can play any post-roll ads. const contentEndedListener = function () { adsLoader.contentComplete(); }; videoContent.onended = contentEndedListener; // Request video ads. const adsRequest = new google.ima.AdsRequest(); adsRequest.adTagUrl = iinfoVastUrls[iinfoVastUrlIndex]; console.log('Preroll advert: ' + iinfoVastUrls[iinfoVastUrlIndex]); videoContent.muted = false; videoContent.volume = 1; // Specify the linear and nonlinear slot sizes. This helps the SDK to // select the correct creative if multiple are returned. // adsRequest.linearAdSlotWidth = prerollWidth; // adsRequest.linearAdSlotHeight = prerollHeight; adsRequest.nonLinearAdSlotWidth = 0; adsRequest.nonLinearAdSlotHeight = 0; adsLoader.requestAds(adsRequest); } function createAdDisplayContainer() { // We assume the adContainer is the DOM id of the element that will house // the ads. prerollDocument.getElementById('videoContent').style.display = 'none'; adDisplayContainer = new google.ima.AdDisplayContainer( prerollDocument.getElementById('adContainer'), videoContent); } function unmutePrerollAdvert() { adVolume = !adVolume; if (adVolume) { adsManager.setVolume(0.3); prerollDocument.getElementById('adMuteBtn').innerHTML = ''; } else { adsManager.setVolume(0); prerollDocument.getElementById('adMuteBtn').innerHTML = ''; } } function onAdsManagerLoaded(adsManagerLoadedEvent) { // Get the ads manager. const adsRenderingSettings = new google.ima.AdsRenderingSettings(); adsRenderingSettings.restoreCustomPlaybackStateOnAdBreakComplete = true; adsRenderingSettings.loadVideoTimeout = 12000; // videoContent should be set to the content video element. adsManager = adsManagerLoadedEvent.getAdsManager(videoContent, adsRenderingSettings); // Add listeners to the required events. adsManager.addEventListener(google.ima.AdErrorEvent.Type.AD_ERROR, onAdError); adsManager.addEventListener( google.ima.AdEvent.Type.CONTENT_PAUSE_REQUESTED, onContentPauseRequested); adsManager.addEventListener( google.ima.AdEvent.Type.CONTENT_RESUME_REQUESTED, onContentResumeRequested); adsManager.addEventListener( google.ima.AdEvent.Type.ALL_ADS_COMPLETED, onAdEvent); // Listen to any additional events, if necessary. adsManager.addEventListener(google.ima.AdEvent.Type.LOADED, onAdEvent); adsManager.addEventListener(google.ima.AdEvent.Type.STARTED, onAdEvent); adsManager.addEventListener(google.ima.AdEvent.Type.COMPLETE, onAdEvent); playAds(); } function playAds() { // Initialize the container. Must be done through a user action on mobile // devices. videoContent.load(); adDisplayContainer.initialize(); // setupDimensions(); try { // Initialize the ads manager. Ad rules playlist will start at this time. adsManager.init(1920, 1080, google.ima.ViewMode.NORMAL); // Call play to start showing the ad. Single video and overlay ads will // start at this time; the call will be ignored for ad rules. adsManager.start(); // window.addEventListener('resize', function (event) { // if (adsManager) { // setupDimensions(); // adsManager.resize(prerollWidth, prerollHeight, google.ima.ViewMode.NORMAL); // } // }); } catch (adError) { // An error may be thrown if there was a problem with the VAST response. // videoContent.play(); } } function onAdEvent(adEvent) { const ad = adEvent.getAd(); console.log('Preroll event: ' + adEvent.type); switch (adEvent.type) { case google.ima.AdEvent.Type.LOADED: if (!ad.isLinear()) { videoContent.play(); } prerollDocument.getElementById('adContainer').style.width = '100%'; prerollDocument.getElementById('adContainer').style.maxWidth = '640px'; prerollDocument.getElementById('adContainer').style.height = '360px'; break; case google.ima.AdEvent.Type.STARTED: window.addEventListener('scroll', onActiveView); if (ad.isLinear()) { intervalTimer = setInterval( function () { // Example: const remainingTime = adsManager.getRemainingTime(); // adsManager.pause(); }, 300); // every 300ms } prerollDocument.getElementById('adMuteBtn').style.display = 'block'; break; case google.ima.AdEvent.Type.ALL_ADS_COMPLETED: if (ad.isLinear()) { clearInterval(intervalTimer); } if (prerollLastError === 303) { playYtVideo(); } break; case google.ima.AdEvent.Type.COMPLETE: if (ad.isLinear()) { clearInterval(intervalTimer); } playYtVideo(); break; } } function onAdError(adErrorEvent) { console.log(adErrorEvent.getError()); prerollLastError = adErrorEvent.getError().getErrorCode(); if (!loadNext()) { playYtVideo(); } } function loadNext() { iinfoVastUrlIndex++; if (iinfoVastUrlIndex < iinfoVastUrls.length) { iinfoPrerollPosition.remove(); playPrerollAd(); } else { return false; } adVolume = 1; return true; } function onContentPauseRequested() { videoContent.pause(); } function onContentResumeRequested() { videoContent.play(); } function onActiveView() { if (prerollContainer) { const containerOffset = prerollContainer.getBoundingClientRect(); const windowHeight = window.innerHeight; if (containerOffset.top < windowHeight/1 && containerOffset.bottom > 0.0) { if (prerollPaused) { adsManager.resume(); prerollPaused = false; } return true; } else { if (!prerollPaused) { adsManager.pause(); prerollPaused = true; } } } return false; } function playYtVideo() { iinfoPrerollPosition.remove(); youtubeIframe.style.display = 'block'; youtubeIframe.src += '&autoplay=1&mute=1'; } }
Upozorníme vás na články, které by vám neměly uniknout (maximálně 2x týdně).
'; document.getElementById('outstream-iframe').onload = function () { setupIframe(); } replayScreen = document.getElementById('iinfoOutstreamReplay'); iinfoOutstreamPosition = document.getElementById('iinfoOutstreamPosition'); outstreamContainer = document.getElementsByClassName('outstream-container')[0]; setupReplayScreen(); } function setupIframe() { outstreamDocument = document.getElementById('outstream-iframe').contentWindow.document; let el = outstreamDocument.createElement('style'); outstreamDocument.head.appendChild(el); el.innerText = "#adContainer>div:nth-of-type(1),#adContainer>div:nth-of-type(1) > iframe { width: 99% !important;height: 99% !important;max-width: 100%;}#videoContent,body{ width:100vw;height:100vh}body{ font-family:'Helvetica Neue',Arial,sans-serif}#videoContent{ overflow:hidden;background:#000}#adMuteBtn{ width:35px;height:35px;border:0;background:0 0;display:none;position:absolute;fill:rgba(230,230,230,1);bottom:-5px;right:25px}"; videoContent = outstreamDocument.getElementById('contentElement'); videoContent.style.display = 'none'; videoContent.volume = 1; videoContent.muted = false; if ( location.href.indexOf('rejstriky.finance.cz') !== -1 || location.href.indexOf('finance-rejstrik') !== -1 || location.href.indexOf('firmy.euro.cz') !== -1 || location.href.indexOf('euro-rejstrik') !== -1 || location.href.indexOf('/rejstrik/') !== -1 || location.href.indexOf('/rejstrik-firem/') !== -1) { outstreamDirectPlayed = true; soundAllowed = true; iinfoVastUrlIndex = 0; } if (!outstreamDirectPlayed) { console.log('OUTSTREAM direct'); setUpIMA(true); } else { if (soundAllowed) { const playPromise = videoContent.play(); if (playPromise !== undefined) { playPromise.then(function () { console.log('OUTSTREAM sound allowed'); setUpIMA(false); }).catch(function () { console.log('OUTSTREAM sound forbidden'); renderBanner(); }); } } else { renderBanner(); } } } function getWrapper() { let articleWrapper = document.querySelector('.rs-outstream-placeholder'); // Outstream Placeholder from RedSys manipulation if (articleWrapper && articleWrapper.style.display !== 'block') { articleWrapper.innerHTML = ""; articleWrapper.style.display = 'block'; } // Don't render OutStream on homepages if (articleWrapper === null) { if (document.querySelector('body.p-index')) { return null; } } if (articleWrapper === null) { articleWrapper = document.getElementById('iinfo-outstream'); } if (articleWrapper === null) { articleWrapper = document.querySelector('.layout-main__content .detail__article p:nth-of-type(6)'); } if (articleWrapper === null) { // Euro, Autobible, Zdravi articleWrapper = document.querySelector('.o-article .o-article__text p:nth-of-type(6)'); } if (articleWrapper === null) { articleWrapper = document.getElementById('sidebar'); } if (!articleWrapper) { console.error("Outstream wrapper of article was not found."); } return articleWrapper; } function setupDimensions() { outstreamWidth = Math.min(iinfoOutstreamPosition.offsetWidth, 480); outstreamHeight = Math.min(iinfoOutstreamPosition.offsetHeight, 320); } /** * Sets up IMA ad display container, ads loader, and makes an ad request. */ function setUpIMA(direct) { google.ima.settings.setDisableCustomPlaybackForIOS10Plus(true); google.ima.settings.setLocale('cs'); google.ima.settings.setNumRedirects(10); // Create the ad display container. createAdDisplayContainer(); // Create ads loader. adsLoader = new google.ima.AdsLoader(adDisplayContainer); // Listen and respond to ads loaded and error events. adsLoader.addEventListener( google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED, onAdsManagerLoaded, false); adsLoader.addEventListener( google.ima.AdErrorEvent.Type.AD_ERROR, onAdError, false); // An event listener to tell the SDK that our content video // is completed so the SDK can play any post-roll ads. const contentEndedListener = function () { adsLoader.contentComplete(); }; videoContent.onended = contentEndedListener; // Request video ads. const adsRequest = new google.ima.AdsRequest(); if (direct) { adsRequest.adTagUrl = directVast; console.log('Outstream DIRECT CAMPAING advert: ' + directVast); videoContent.muted = true; videoContent.volume = 0; outstreamDirectPlayed = true; } else { adsRequest.adTagUrl = iinfoVastUrls[iinfoVastUrlIndex]; console.log('Outstream advert: ' + iinfoVastUrls[iinfoVastUrlIndex]); videoContent.muted = false; videoContent.volume = 1; } // Specify the linear and nonlinear slot sizes. This helps the SDK to // select the correct creative if multiple are returned. // adsRequest.linearAdSlotWidth = outstreamWidth; // adsRequest.linearAdSlotHeight = outstreamHeight; adsRequest.nonLinearAdSlotWidth = 0; adsRequest.nonLinearAdSlotHeight = 0; adsLoader.requestAds(adsRequest); } function setupReplayScreen() { replayScreen.addEventListener('click', function () { iinfoOutstreamPosition.remove(); iinfoVastUrlIndex = 0; outstreamInit(); }); } /** * Sets the 'adContainer' div as the IMA ad display container. */ function createAdDisplayContainer() { // We assume the adContainer is the DOM id of the element that will house // the ads. outstreamDocument.getElementById('videoContent').style.display = 'none'; adDisplayContainer = new google.ima.AdDisplayContainer( outstreamDocument.getElementById('adContainer'), videoContent); } function unmuteAdvert() { adVolume = !adVolume; if (adVolume) { adsManager.setVolume(0.3); outstreamDocument.getElementById('adMuteBtn').innerHTML = ''; } else { adsManager.setVolume(0); outstreamDocument.getElementById('adMuteBtn').innerHTML = ''; } } /** * Loads the video content and initializes IMA ad playback. */ function playAds() { // Initialize the container. Must be done through a user action on mobile // devices. videoContent.load(); adDisplayContainer.initialize(); // setupDimensions(); try { // Initialize the ads manager. Ad rules playlist will start at this time. adsManager.init(1920, 1080, google.ima.ViewMode.NORMAL); // Call play to start showing the ad. Single video and overlay ads will // start at this time; the call will be ignored for ad rules. adsManager.start(); // window.addEventListener('resize', function (event) { // if (adsManager) { // setupDimensions(); // adsManager.resize(outstreamWidth, outstreamHeight, google.ima.ViewMode.NORMAL); // } // }); } catch (adError) { // An error may be thrown if there was a problem with the VAST response. // videoContent.play(); } } /** * Handles the ad manager loading and sets ad event listeners. * @param { !google.ima.AdsManagerLoadedEvent } adsManagerLoadedEvent */ function onAdsManagerLoaded(adsManagerLoadedEvent) { // Get the ads manager. const adsRenderingSettings = new google.ima.AdsRenderingSettings(); adsRenderingSettings.restoreCustomPlaybackStateOnAdBreakComplete = true; adsRenderingSettings.loadVideoTimeout = 12000; // videoContent should be set to the content video element. adsManager = adsManagerLoadedEvent.getAdsManager(videoContent, adsRenderingSettings); // Add listeners to the required events. adsManager.addEventListener(google.ima.AdErrorEvent.Type.AD_ERROR, onAdError); adsManager.addEventListener( google.ima.AdEvent.Type.CONTENT_PAUSE_REQUESTED, onContentPauseRequested); adsManager.addEventListener( google.ima.AdEvent.Type.CONTENT_RESUME_REQUESTED, onContentResumeRequested); adsManager.addEventListener( google.ima.AdEvent.Type.ALL_ADS_COMPLETED, onAdEvent); // Listen to any additional events, if necessary. adsManager.addEventListener(google.ima.AdEvent.Type.LOADED, onAdEvent); adsManager.addEventListener(google.ima.AdEvent.Type.STARTED, onAdEvent); adsManager.addEventListener(google.ima.AdEvent.Type.COMPLETE, onAdEvent); playAds(); } /** * Handles actions taken in response to ad events. * @param { !google.ima.AdEvent } adEvent */ function onAdEvent(adEvent) { // Retrieve the ad from the event. Some events (for example, // ALL_ADS_COMPLETED) don't have ad object associated. const ad = adEvent.getAd(); console.log('Outstream event: ' + adEvent.type); switch (adEvent.type) { case google.ima.AdEvent.Type.LOADED: // This is the first event sent for an ad - it is possible to // determine whether the ad is a video ad or an overlay. if (!ad.isLinear()) { // Position AdDisplayContainer correctly for overlay. // Use ad.width and ad.height. videoContent.play(); } outstreamDocument.getElementById('adContainer').style.width = '100%'; outstreamDocument.getElementById('adContainer').style.maxWidth = '640px'; outstreamDocument.getElementById('adContainer').style.height = '360px'; break; case google.ima.AdEvent.Type.STARTED: window.addEventListener('scroll', onActiveView); // This event indicates the ad has started - the video player // can adjust the UI, for example display a pause button and // remaining time. if (ad.isLinear()) { // For a linear ad, a timer can be started to poll for // the remaining time. intervalTimer = setInterval( function () { // Example: const remainingTime = adsManager.getRemainingTime(); // adsManager.pause(); }, 300); // every 300ms } outstreamDocument.getElementById('adMuteBtn').style.display = 'block'; break; case google.ima.AdEvent.Type.ALL_ADS_COMPLETED: if (ad.isLinear()) { clearInterval(intervalTimer); } if (outstreamLastError === 303) { if (isBanner) { renderBanner(); } else { replayScreen.style.display = 'flex'; } } break; case google.ima.AdEvent.Type.COMPLETE: // This event indicates the ad has finished - the video player // can perform appropriate UI actions, such as removing the timer for // remaining time detection. if (ad.isLinear()) { clearInterval(intervalTimer); } if (isBanner) { renderBanner(); } else { replayScreen.style.display = 'flex'; } break; } } /** * Handles ad errors. * @param { !google.ima.AdErrorEvent } adErrorEvent */ function onAdError(adErrorEvent) { // Handle the error logging. console.log(adErrorEvent.getError()); outstreamLastError = adErrorEvent.getError().getErrorCode(); if (!loadNext()) { renderBanner(); } } function renderBanner() { if (isBanner) { console.log('Outstream: Render Banner'); iinfoOutstreamPosition.innerHTML = ""; iinfoOutstreamPosition.style.height = "330px"; iinfoOutstreamPosition.appendChild(bannerDiv); } else { console.log('Outstream: Banner is not set'); } } function loadNext() { iinfoVastUrlIndex++; if (iinfoVastUrlIndex < iinfoVastUrls.length) { iinfoOutstreamPosition.remove(); outstreamInit(); } else { return false; } adVolume = 1; return true; } /** * Pauses video content and sets up ad UI. */ function onContentPauseRequested() { videoContent.pause(); // This function is where you should setup UI for showing ads (for example, // display ad timer countdown, disable seeking and more.) // setupUIForAds(); } /** * Resumes video content and removes ad UI. */ function onContentResumeRequested() { videoContent.play(); // This function is where you should ensure that your UI is ready // to play content. It is the responsibility of the Publisher to // implement this function when necessary. // setupUIForContent(); } function onActiveView() { if (outstreamContainer) { const containerOffset = outstreamContainer.getBoundingClientRect(); const windowHeight = window.innerHeight; if (containerOffset.top < windowHeight/1 && containerOffset.bottom > 0.0) { if (outstreamPaused) { adsManager.resume(); outstreamPaused = false; } return true; } else { if (!outstreamPaused) { adsManager.pause(); outstreamPaused = true; } } } return false; } let outstreamInitInterval; if (typeof cpexPackage !== "undefined") { outstreamInitInterval = setInterval(tryToInitializeOutstream, 100); } else { const wrapper = getWrapper(); if (wrapper) { let outstreamInitialized = false; window.addEventListener('scroll', () => { if (!outstreamInitialized) { const containerOffset = wrapper.getBoundingClientRect(); const windowHeight = window.innerHeight; if (containerOffset.top < windowHeight / 1 && containerOffset.bottom > 0.0) { outstreamInit(); outstreamInitialized = true; } } }); } } function tryToInitializeOutstream() { const wrapper = getWrapper(); if (wrapper) { const containerOffset = wrapper.getBoundingClientRect(); const windowHeight = window.innerHeight; if (containerOffset.top < windowHeight / 1 && containerOffset.bottom > 0.0) { if (cpexPackage.adserver.displayed) { clearInterval(outstreamInitInterval); outstreamInit(); } } } else { clearInterval(outstreamInitInterval); } } }
OSZAR »