Jiří Tlapák (Tlapnet): Největším problémem trhu je cenový dumping

30. 9. 2024
Doba čtení: 10 minut

Sdílet

Jiří Tlapák - Tlapnet
Autor: Jiří Tlapák
Jiří Tlapák - Tlapnet
S šéfem regionálního poskytovatele připojení o stavbě optiky, dotacích, kontrolách z ČTÚ, bobtnání smluv ze zákazníky nebo cenách připojení.

Hojně používaná 60gigahertzová technologie i v hůře dostupných lokalitách nabízí podobný užitek jako optické propojení, říká jednatel regionálního operátora Tlapnet Jiří Tlapák. Stávající ceny telekomunikačních služeb považuje za stlačené pod hranici dumpingu. „Když pojedete kamkoliv do ciziny, internet tam stojí mnohem víc,“ dodává.

TIP: Slastem i strastem, které zažívají lokální hráči na českém trhu, se věnujeme v seriálu Jak žijí regionální operátoři

Působíte ve velké části východních Čech i v Moravskoslezském kraji. Nedá mi to se nezeptat, jak činnost vaší firmy ovlivnily nedávné povodně.

Přímo jsme žádnou infrastrukturu zatopenu neměli. V regionech byly zasaženy místní služby, nějaká lokální datacentra. Řešili jsme to zálohami. Našich klientů se to ale nijak zvlášť nedotklo. Tam, kde lidé měli problém s povodněmi, řešili trochu jiné starosti, než jestli jim funguje internet.

TIP: Podívejte se, jak čeští operátoři bojovali s velkou vodou:

Jaké technologie pro poskytování internetu používáte?

V podstatě všechno, co je na trhu k dispozici. To znamená mikrovlny v licenčních i bezlicenčních pásmech, samozřejmě optickou infrastrukturu i kabelové spojení. Řekl bych, že není nic, co bychom nepoužívali z principu. Co můžeme, co dává ekonomický smysl, k čemu máme přístup, to používáme.

A je nějaká technologie, kterou upřednostňujete, kterou se snažíte zákazníkům nabízet na úkor jiné?

Každá lokalita a obchodní případ má svá specifika. V dnešní době každý propaguje optickou infrastrukturu, nicméně ne vždy je tato technologie použitelná. Třeba v oblastech Beskyd se spoustou kopců, členitým terénem, je dost problematické vymýšlet propojování i bezdrátem. Mnohdy se snažíme používat kombinace, kde jsou dílčí celky, které se dají rozumně pospojovat. 

V dnešní době je hojně používaná 60gigahertzová technologie. Ta ve volném pásmu nabízí poměrně zajímavé možnosti i v hůře dostupných lokalitách, s parametry nabízejícími dostatečný ekvivalent optické infrastruktury. Troufám si říct, že mnohdy dokážeme zákazníkům skrze mikrovlnné technologie nabízet srovnatelnou službu jako na optice i v místech, kde není jednoduché optiku zřizovat.

Ing. Jiří Tlapák, MBA 

Firmu zakládal v roce 2004 spolu se svým otcem s cílem zajistit pokrytí Železných hor a okolí Ronova nad Doubravou, odkud oba pocházeli. Nyní pokrývá velkou část východních Čech a severomoravského kraje a působí i na Slovensku. Internet přivádí do více než 80 tisíc domácností. Od roku 2012 je členem ISP Alliance.

Telekomunikační operátoři měli možnost čerpat dotace NGA pro pokrytí bílých míst. Vy sami jste se pokusili na peníze z tohoto programu dosáhnout?

Zajímali jsme se o to, ale ve výsledku jsme to vyhodnotili tak, že to není pro firmu naší velikosti úplně zajímavé. Je to pro větší operátory, firmy typu CETIN a další, které mají projekční možnosti a větší územní rozsah. My se držíme té cesty, že si všechno stavíme z vlastních prostředků, používáme na to vlastní nebo bankovní kapitál.

A uvítali byste, kdyby stát otevřel program zaměřený na střední providery než – jak říkáte – velké operátory?

O dotace se poměrně dost zajímám a velké množství těch dotací je z mého pohledu špatně koncipovaných. Nejsou účelově zaměřené tam, kde by byly opravdu potřeba. Zatím jsme neviděl příliš dotačních programů, které by splnily svůj účel. Vesměs si na to sáhnou velké firmy a v některých případech to dost pokřivuje trh. Muselo by to mít hlavu a patu a muselo by to být promyšlené do detailů.

Kdybyste měl státu radit, jak jinak by měl nastavit parametry dotace, aby to splňovalo účelovost, o které mluvíte, jak by zněla vaše rada?

Hlavně je důležité posoudit, kde ta dotace je opravdu potřeba, jak ve skutečnosti vypadá situace na místě, kam by měly peníze přitéct.

Tím narážíte na bílá místa, která regulátor v rámci programu NGA mapoval?

Spíš narážím na to, že jsou různé technologie, kde máte nějakým způsobem definovat dostupnost, a ono to není z principu věci úplně jednoduché. Programy jsou víceméně šité na míru obrovskému operátorovi nebo národním providerům. Menší firma napřed udělá jednu lokalitu, pak teprve bude zjišťovat, jestli se jí to vlastně vyplatilo, nebo ne. Takže popravdě jsem ani nezkoumal, kolik regionálních firem se dalo cestou dotací, že si to zkusilo nebo někde zkouší. Spíš všude vídám CETIN, který se zaměřuje na dotační tituly. Neříkám, že to není potřeba, ale myslím si, že by se ty peníze daly vynaložit mnohem efektivněji.

Jsou ta měřítka rychlosti definovaná státem správně?

My si umíme pohlídat svůj region, víme, kde optika má smysl, a kde naopak nutná není. Protože v mnoha případech lidé mají přístup k internetu naddimenzovaný. Když se podíváte do zahraničí, sice vídám různé statistiky a tabulky, jak je to u nás špatné, ale když pak se rozjedete za hranice, zjistíte, že to tak špatné není a cena už vůbec špatná není.

Na Lupě jsme nedávno měli anketu, kde se několik tisíc čtenářů vyjadřovalo, jaká rychlost je pro ně dostatečná. Jak je to z pohledu providera? Co je pro běžnou českou domácnost dostatečně rychlý internet?

Záleží to na tom, co je to za uživatele, jaká je to rodina, jestli má děti, jak staří jsou členové té rodiny. Ale nevidím zásadní rozdíl mezi tím, když má někdo dejme tomu 200 nebo 300 Mb/s, nebo když má někdo gigabit. Na tom už jsou lidé v podstatě zvyklí internet používat určitým způsobem a pak už nedokážete pobrat tolik věcí naráz.

A není to na úkor uživatelského zážitku, že v momentě, kdy tu rychlost člověk potřebuje, tak ji má, byť ji nevyužívá po celou dobu? Že je to designované na tu špičku, kdy potřebuje mít maximum kapacity?

Podle toho, co jsme pozorovali, si nemyslím, že by lidé byli nešťastní z toho, že mají 100 Mb/s a nemají třeba ten gigabit. Není to úplně jednoduše vztáhnutelné na všechny uživatele. Možná když chytnete nějakého teenagera, který potřebuje mít všechno nejrychlejší, nejlepší, tak samozřejmě řekne, že chce jen optiku. 

My tu situaci zažíváme i na Slovensku. Tam velcí operátoři udělali obrovskou reklamu optice, ale když jdete do detailu, zjistíte, že spousta koncových zákazníků vůbec neví a nechápe, jakým médiem jsou k internetu připojeni. Pro ně je důležité, že to funguje, a když nefunguje, tak mají nějakou možnost to přes telefon vyřešit. Takových uživatelů je pořád hodně.

Jiří Tlapák

Autor: Jiří Tlapák

Kde vám dává optika smysl?

Když to děláte na zelené louce nějakého developerského projektu, kde vzniknou nové domy, není to problém a všichni čekají, že se tam optika připraví. Ale když máte zasíťovat objekty, které jsou už desítky let postavené, bydlí v nich lidé, úplně se netváří na to, že přes zahrádku, nebo prostorem, který mají upravený, bude muset projít optické vlákno, mnohdy se setkáváme s tím, že řeknou, že to nechtějí. Že radši budou využívat anténu někde na komíně, protože jim těch 100 Mb/s přes bezdrát stačí.

Je to nějaký masovější jev, že lidé odmítají optiku?

Hodně záleží na typu obce a výstavby. Někde máte stavby namáčknuté k silnicím, nebo těm rozvodům, někde jsou předzahrádky, takže domy jsou posunuté až do zadních linií, a tam je to většinou problém. Protože abyste se dostal k tomu domu, musíte někudy jít třeba 30 nebo 50 metrů. A lidi tam mají dlažby, záhony. Určité procento lidí v každé lokalitě je těžké přesvědčit, aby si optiku nechali zavést, když už to tam pokládáte. Takže někdy to prostě máme připravené a čeká se na to, až změní pohled, nebo dokud ten bezdrát nevypnete.

A když už s tím souhlasí, je pro vás jednoduché stavět optické sítě, pomohla vám například legislativa, nebo byste uvítali jiný přístup ze strany obcí nebo státu?

Nemyslím, že by se situace nějak zásadně změnila. Když chcete lokalitu pokrýt, ať už ve městě, nebo na vesnici, vždy potřebujete součinnost a vůli té municipality. Pokud tam je, tak se dá fungovat v rámci stavebního zákona, ať už současného, nebo minulého, a to dílo se dá zrealizovat. Naopak, pokud bychom to tlačili za každou cenu i proti vůli politického vedení, tak stejně žádné zjednodušení nepomůže.

Setkáváte se i s nevolí vedení obce, že řeknou „optiku nechceme“? Čím to zdůvodňují?

Je to různé, někde to mohou být tlaky konkurence, která tam už je zaháčkovaná. Je navázaná na obec a třeba mají příslib, že tam internet budou dělat oni. V minulosti jsme měli lokality, kam jsme se nemohli dostat, protože nás tam nechtěli, a pak najednou to bylo zasíťované někým jiným. Mohou tam být i důvody jiné, někdy politické, třeba že není úplně vhodné před volbami nebo v nějakém období rozkopávat část obce nebo města. A pak je to i estetický pohled. Jsou lokality, které z dotací opraví, obnoví povrchy, a pak se jim logicky nelíbí, že by tam chtěl přijít někdo, kdo to zas bude chtít rozkopávat.

Jste provider střední velikosti, jak intenzivně vnímáte regulatorní zátěž?

Před 20 lety měla smlouva na připojení k internetu jedna až dvě strany A4. Dnes smluvní dokumentace zahrnuje samotnou smlouvu, všeobecné podmínky, tabulky rychlostí, rozhraní, shrnutí smlouvy, informace o změně poskytovatele, prohlášení o ochraně osobních údajů a další povinnosti. Desítky stran dokumentů musí naplňovat stovky legislativních požadavků. A brzy přibydou další, v souvislosti s implementací směrnice NIS2. 

K tomu se vám přidává výkaznictví a sběr dat, která často nedávají smysl. Třeba o dostupnosti bezdrátových sítí až na úroveň adresních míst. Každý, kdo problematice rozumí, ví, že skutečná dostupnost závisí na mnoha podmínkách, které se mění v čase, a bez technického šetření u nich nelze zaručit stoprocentní přesnost. Přesto naše regulace s tím počítá. Pod hrozbou sankcí se sbírají data pro nefunkční a uživatelsky nepřívětivý státní srovnávač telekomunikačních služeb.

Pociťujete, že s rostoucí velikostí firmy se na vás Český telekomunikační úřad (ČTÚ) více zaměřuje?

Ano, ten pocit máme, a poměrně intenzivní.

Zaznamenáváte z jejich strany nějaké častější kontroly?

Chodí na kontroly, kontrolují veškeré povinnosti i z nařízení, ať už je to nějaké uveřejňování informací na webu, smluvní dokumentace, dodržování frekvencí pásem. Kontroly a na ně navazující správní řízení jsou poměrně časté, velice intenzivní, a víme, že u menších konkurentů neprobíhají v takové míře. Máme přehled, co se na trhu děje, a nepřijde nám v pořádku, že některé podnikatele kontrolují víc a některé méně. Bylo by dobré, kdyby se ČTÚ zaměřoval na skutečné problémy.

Blíží se nový zákon o kybernetické bezpečnosti transponující kyberbezpečnostní směrnici NIS2. Bude se vás to týkat? Stanete se subjektem podléhajícím regulaci? Jak se na to dopředu připravujete?

Nás se to týkat asi bude, kolegové už se tím zabývají. Minimálně to přinese další zátěž, ale nebereme to na lehkou váhu. Prostě zase další věc z mnoha. Bude to znamenat finanční náklady pro providery, kteří budou používat v síti prvky, u kterých stát řekne, že je nechce.

Vás by se dotklo, kdyby NÚKIB čínské dodávky v telekomunikačních sítích na našem území zakázal?

Samozřejmě, nejsme určitě ti, kteří používají ryze nečínské produkty. Minimálně v nějaké části sítě by muselo dojít k výměnám, jako u všech ostatních v tomhle segmentu.

Z vašeho pohledu, co trápí trh telekomunikačních služeb, je to funkční trh?

Svým způsobem funkční je, ale jako největší problém vnímám cenový dumping. Vlivem inflace dochází ke zdražení zdrojů a poskytovatelé dlouhodobě drží ceny na minimálních hodnotách. Takže máme internet velmi levný. Když půjdete kamkoliv do zahraničí, základní internetové připojení tam stojí mnohem víc. 

Posledních pět let, možná i déle, jsme tu neviděli, že by někdo zásadně zdražoval služby, ať už mobilní operátoři, nebo regionální provideři. Jestli růst cen nastal, tak v řádech pár korun. Až teď začaly vlny zdražování, když vstupy už jsou opravdu neúnosné. Pokud nějaký provider prodával internet za 300 nebo 350 korun, zjistil, že mu z toho už moc nezbývá, když zaplatí DPH a poplatí všechny náklady.

Navíc dochází k tomu, že velcí hráči cenu opět stlačují na nesmyslné hodnoty, kde se pohybují třeba kolem stokoruny měsíčně bez daně za přípojku o poměrně vysokých parametrech. A tady chybí nějaká regulace. Institut, který by řešil, že takto to být z principu nemůže. Jenže problém je definice toho samotného trhu, jestli to je trh regionální, a druhá věc, že když někdo zavede dumping, v tu chvíli nemá na trhu majoritu. Až po nějakou dobu působení těchto praktik se stane významným hráčem. Ale pak už zas tu cenu podstřelovat nepotřebuje, protože zlikviduje konkurenci do takové míry, že už pro něj konkurencí není.

CIF25_SE_terc

Vy sami jste se stali třeba terčem zájmu CETINu, který se v minulosti snažil skupovat regionální providery?

Jestli myslíte přímo zájem o naši společnost, tak se to dělo samozřejmě skrz různé agentury. Pokusy tady byly a nějaké i jsou. Ale nemáme zájem firmu prodávat. Nemyslím si, že by nadešel čas. Kdybychom to asi prodávat chtěli, kupec se vždycky nějaký najde, ten hlad na trhu je, každopádně pociťujeme, že na trhu konsolidace probíhá. Z našich významných konkurentů nezbývá mnoho, kteří by ještě nebyli něčím nebo někým pohlceni.

  • 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

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 »