Nová Opera vyroste na základech projektů Chromium a WebKit

27. 2. 2013
Doba čtení: 11 minut

Sdílet

Ilustrační obrázek
Autor: Depositphotos – stori
Ilustrační obrázek
Multiplatformní webový prohlížeč Opera po 18 letech opouští své vlastní jádro Presto. Nové technologické pozadí jednoho z tradičních browserů bude nově založeno na open source projektech WebKit a Chromium. Proč dochází k těmto změnám, co znamenají pro uživatele a co pro celé webové prostředí?

Norská společnost Opera Software, tvůrce multiplatformních prohlížečů, se po nějakém čase připomněla světu. Nikoliv však dlouho očekávanou novou verzí desktopového prohlížeče s kódovým označením Marlin (Mečoun), ale odhozením vlastní dlouhé roky budované technologie, propouštěním vývojářů a podivnou změnou v komunikaci. Ale popořadě.

„Kde jsou testovací buildy nové významné verze prohlížeče Opera? Kde jsou sliby nových funkcí a podpory nových technologií?“ ptal se jistě nejeden čtenář blogu týmu, který se stará o vývoj Opery pro desktop. Blog, který tradičně chrlí zprávy o velkých a smělých plánech, se omezil jen na příspěvky o opravách v současné generaci prohlížeče.

Pravděpodobný důvod se uživatelé, ale i weboví vývojáři a třeba i tvůrci rozšíření, dozvěděli na jiném z blogů na komunitním webu My Opera. Opera Software hodlá opustit své současné vlastní jádro Presto, na němž pracuje již od roku 1995. Teď ho ale vymění za WebKit a hodlá se zapojit do open source projektu Chromium, z něhož chce převzít engine V8 pro zpracování kódu v jazyce JavaScript.

Stane se Opera jen klonem prohlížeče Google Chrome?

Samozřejmě, že každého asi nyní napadne otázka, jestli máme čekat jen další klon prohlížeče Google Chrome, který de facto kopíruje vývoj projektu Chromium. Prý ne. Tvrdí to Bruce Lawson, jeden z vývojářů společnosti Opera Software známý komunitě spíše pod přezdívkou Odin. Opera Software prý všechny své vlastní vymoženosti ze stávajícího prohlížeče s jádrem Presto přenese do nového prohlížeče požívajícího výhod jádra WebKit a projektu Chromium.

Opera s jádrem Presto, dlouho už ne

Proč však Opera Software opouští po 18 letech vlastní jádro Presto?  Bruce Lawson vysvětluje, že Presto vzniklo v době, kdy dominoval Netscape Navigator a začínal vystrkovat růžky Internet Explorer. Jít svou vlastní cestou prý tehdy byla jediná možnost, jak začít pracovat na prohlížeči, který bude ctít webové standardy a přispívat k dalšímu rozvoji webu.

Nyní je tu ovšem WebKit, který podle Bruce Lawsona dosahuje takové úrovně podpory webových standardů, o které se na počátku vývoje jádra Presto lidem ve společnosti Opera Software prý ani nezdálo.  S přechodem na WebKit se tak norská firma bude moci více soustředit na rozvoj funkcí prohlížeče, namísto vytváření těch samých funkcí pro vlastní jádro, které jiné dostupné jádro již nabízí.

Tolik k důvodům, které zmínil Bruce Lawson. Jsou pochopitelné a akceptovatelné, nicméně je poněkud zarážející, že k tak významné události Opera Software nevydal žádnou tiskovou zprávu a omezila se jen na příspěvek na blogu jednoho ze svých vývojářů. Skoro se zdá, jako by se norská firma nechtěla v kompletní změně technologického pozadí svého prohlížeče příliš „šťourat“.

Opuštění vlastní technologie lze totiž prezentovat jako rezignaci. Není tajemstvím, že například hardwarová akcelerace se stala hodně tvrdým oříškem. V Opeře je pořád v experimentálním stádiu, ostatní konkurenční prohlížeče ji nabízejí již delší dobu. Přitom vývojáři původně přinášeli velkoústá prohlášení o nejvýkonnější hardwarové akceleraci vůbec.

Skoncování s vlastním jádrem lze též interpretovat jako pokus povozit se na vlně vzedmuté prohlížečem Google Chrome. V této souvislosti je zajímavé, že nikde nebylo oficiálně prezentováno, proč padla volba právě na WebKit a nikoliv na rovněž otevřené Gecko, které vyvíjí Mozilla. Rozhodly technologické důvody? Pokud ano, pak jaké? Nebo je Chromium prostě nyní více „sexy“? Pak ale nedá smysl zdrženlivá komunikační strategie.

Chromium: je prostě sexy

Opera Software mohl sáhnout po takříkajíc surovém jádru WebKit a ne se hned přihlásit k celému projektu Chromium. Jenže, jak již bylo uvedeno, hodlá adoptovat i engine V8, který je součástí právě projektu Chromium. Je to jen spekulace, ale zřejmě si Opera z projektu Chromium nebude brát jen technologické prvky, ale i funkce.

Těm následně dělá reklamu Google Chrome, který je prakticky derivátem projektu Chromium doplněným o ochranné známky Googlu. A pravdou je, že marketingová síla Googlu je úplně někde jinde než marketingová síla Mozilly coby tvůrce „referenčního“ prohlížeče s jádrem Gecko. 

Co znamená přechod na WebKit, respektive Chromium?

Vzhledem k tomu, co zaznělo výše, může být změna technologického pozadí prohlížečů norské firmy pro ni samotnou a její uživatele může být jedině změna k lepšímu. Vývojáři Opery se skutečně budou moci více zaměřit na funkce prohlížeče oslovující přímo koncové uživatele. Zlepší se i výkon prohlížeče díky odladěné hardwarové akceleraci a enginu V8. Rovněž i podpora webových standardů či nových slibných technologií jako je WebRTC. 

V neposlední řadě se pak zlepší kompatibilita. Opera není řadou webových služeb oficiálně podporována, takže situace je taková, že v zájmu zachování konkurenceschopnosti se Opera při problémech s kompatibilitou mnohdy musí přizpůsobovat webovým službám, nikoliv webové služby Opeře. Je to dáno tím, že Opera dosud používala vlastní jádro, které kopíruje tržní zastoupení samotné Opery, takže mnoha tvůrcům webových služeb zkrátka nestojí za pozornost.

To se s přechodem na Chromium dramaticky změní. Jak známo, Chromium je totiž základem pro Google Chrome, který s ostrými lokty a tržní silou Googlu pomaličku (a bohužel) od Internet Exploreru přebírá roli „jediného správného prohlížeče“. Navíc jádro WebKit je na trhu významně zastoupeno nejen díky prohlížeči Googlu. Používá jej také Safari z dílny Applu se silným postavením na poli mobilních zařízení.

Opera získá v HTML5 testu 404 bodů…

Safari má také nezanedbatelné postavení v oblasti PC, kde je systémovým prohlížečem OS X, druhé nejrozšířenější platformy pro PC současnosti. Analytici přitom říkají, že v klíčovém firemním sektoru během několika let bude OS X přijímán stejně jako MS Windows. WebKit pak používá také Maxthon, ambiciózní webový prohlížeč, který je na platformě MS Windows pátým nejrozšířenějším.

WebKit je tedy jasnou jedničkou. Konkurovat mu může jedině jádro Trident, které Microsoft používá ve svém browseru Internet Explorer. Gecko je bohužel až tím třetím vzadu. Sečteno a podtrženo, Opera Software nemůže na přechodu na Chromium prodělat. Stačí jen nabalit na získané otevřené zdrojové kódy funkcionalitu, na kterou je současná uživatelská komunita zvyklá a právě kvůli ní používá Operu.

Krok tvůrců Opery je ovšem pozitivní i pro celé webové prostředí, jelikož se zmírní fragmentace. Weboví vývojáři budou moci zapomenout na jedno „exotické“ jádro. Pozornost bude možné upřít jen na WebKit, Trident a Gecko. Opera Software navíc prostřednictvím Bruce Lawsona slibuje, že nehodlá z projektů WebKit a Chromium jenom týt, ale chce do nich aktivně přispívat. 

Pokud dodrží slovo, pak na technologii pro moderní prohlížeče a potažmo moderní web bude pracovat více zkušených vývojářů, což je jedině plus. Jenže okrajových prohlížečů využívajících Gecko či WebKit je nespočet, ovšem jejich přispění k vývoji je minimální. Na projektech spíše parazitují. Uvidíme tedy, jak Opera Software dodrží slovo. 

Připravil WebKit o práci desítky vývojářů?

Firma se totiž zbavuje vývojářů. Firmu opustí 90 zaměstnanců, tedy téměř 10 %. Většina z nich jsou přitom vývojáři. Otázkou je, jestli vývojáři odchází pro nadbytečnost po přechodu na WebKit a Chromium, nebo Opera Software přechází na WebKit a Chromium, protože už nadále nechce / nemůže platit tolik vlastních vývojářů. Snadno zde lze zaměnit příčinu s následkem. 

V dnešní době hledá úspory snad každá firma a mnohé jdou právě cestou propouštění, které v nebývalé síle v posledních letech zasáhlo mnohem větší ryby v IT rybníce než je norská společnost Opera Software. Není však přechod na WebKit + Chromium a zeštíhlování firmy přípravou na prodej?

… s WebKitem si Opera polepší na 463 bodů

Před časem se čile spekulovalo, že se o tvůrce nejvýznamnějšího evropského webového prohlížeče zajímá Facebook. Pro něj by v souboji s Googlem vývoj vlastního prohlížeče dával smysl a Opera Software je jediným z větších hráčů, který je k mání. Lars Bilesen, nynější šéf společnosti Opera Software, však pro norský server Digi.no rezolutně popřel, že by Opera Software byl nyní na prodej. 

Opera Software „spolkl“ tvůrce prohlížeče SkyFire

Lars Bilesen argumentuje, že firma na prodej by neinvestovala 155 milionu dolarů ve formě akvizice společnosti SkyFire. Opera Software se touto akvizicí zbavil jednoho z konkurentů na mobilním poli. SkyFire totiž stojí za stejnojmenným prohlížečem pro iOS a Android. Nejde tu ale o klasické zlikvidování konkurence. To by pro nevelkou norskou firmu bylo drahé řešení konkurenčního boje. Akvizicí má Opera Software posílit jak v oblasti technologií, tak v oblasti kontaktů.  

Prohlížeč SkyFire má poměrně významné postavené v zámoří ve Spojených státech díky spolupráci jeho tvůrců s tamními mobilními operátory. Prohlížeč totiž dokáže díky cloudové technologii Rocket Optimizer, kterou Opera Software v rámci akvizice rovněž získal, výrazně snížit datové přenosy v mobilních sítích. Komprimuje online video a do chytrých mobilů a tabletů tak přes sítě operátorů proudí méně dat.

To vzhledem k datovým limitům ocení i uživatelé. Lars Bilesen na adresu prohlížeče SkyFire pěl chválu také, co se optimalizace pro tablety týče. Opera Mobile je prohlížeč spojený spíše s chytrými mobily. Pro tablety existují lepší volby, což je pro Opera Software nemilé, protože prodejnost tabletů neustále překonává očekávání a jde dnes o klíčový tržní segment. Náskok konkurence se nemusí později dát již dohnat. 

Opera Software tak jistě jako svou hlavní zbraň bude chtít v budoucnu skloubit získanou technologii Rocket Optimizer se svou vlastní technologií používanou v rámci služby Opera Turbo známé z desktopového prohlížeče Opera i mobilního prohlížeče Opera Mobile. Obě snižují objem dat přenášených do koncového zařízení ze serverů, kde dochází ke kompresi těchto dat.

Prohlížeč, který dokáže výrazně snížit objem přenášených dat v mobilních sítích, může být pro Opera Software z hlediska byznysu mnohem zajímavější, než svádění boje o pozice na osobních počítačích, kde je přes letité snažení Opera stále na okraji zájmu uživatelů. Nepomohla ani u Evropské komise vymodlená ballot screen. Naopak na mobilní scéně se Opeře daří a akvizice firmy SkyFire může její prapor pozvednout ještě výše.

K uživatelům se může dostat díky spolupráci s výrobci mobilů a mobilními operátory. Prohlížeč, který vysoce efektivně snižuje datový provoz, je totiž žádán jak uživateli, tak operátory a potažmo tedy i výrobci mobilů. Operátoři musí kalkulovat s kapacitou své sítě, kvůli které svazují zákazníky datovými limity. Zákazníci pak musí s těmito limity hospodařit či spíše bojovat. 

A výrobci se v tomto ohledu rádi přizpůsobí jak operátorům, tak zákazníkům. To je šance porazit mobilní Google Chrome na jeho domovské platformě. Jelikož je Android otevřený, výrobci si mohou předinstalovat do svých zařízení prohlížeč dle libosti. A platforma jako taková je alternativním prohlížečům otevřená na rozdíl od iOS či okrajových Windows Phone. 

Kdy dojde k přechodu na WebKit (Chromium)?

Teoreticky již velmi brzy. Do Barcelony by na Mobile World Congress 2013 měl Opera Software přijet prezentovat nový prohlížeč pro Android. Mohlo by jít o Opera Ice, tedy počátkem roku představený browser, o kterém se již několik týdnů ví, že jej bude pohánět právě WebKit. Veřejnosti měl být ukázán v únoru, což lze na barcelonské akci Mobile World Congress 2013 stále stihnout.

Pochyby však vyvolává stažení videí z YouTube, na kterých byla zachycena vývojová verze v akci. Dokonce i jejich kopií. Opera Software uplatnil svá autorská práva a požádal správce YouTube o smazání těchto videí. Proč? Jde jen o přípravu na velké odhalení anebo se plány za pochodu mění a je třeba zamést stopy po slepé větvi vývoje? Uvidíme již velmi brzo.

Jasné a pochopitelné je, že se Opera Software definitivně stáhne z historických mobilních platforem jako je Symbian či Windows Mobile, které již i jejich tvůrci poslali na odpočinek. Ostatně už nějaký ten pátek Opera Software vyvíjí své mobilní prohlížeče jen pro chytrá zařízení s moderními systémy Android a iOS a běžné mobily podporující J2ME. Z hlediska byznysu je budoucnost už jenom zde, pokud se neobjeví nový silný hráč otevřený pro alternativní prohlížeče. 

Kdy Opera s novými „vnitřnostmi“ dorazí na osobní počítače, prozatím zůstává tajemstvím. Obecným oficiálním termínem je letošní rok, což je poněkud vágně definovaný termín na firmu, která své kroky vždy prezentovala poměrně transparentně. Opera Software avizuje, že ve druhém čtvrtletí přijde s novým desktopovým produktem, ale překvapivě nechce odpovědět na otázku, jestli to bude Opera s novým technologickým pozadím.

Rojí se tedy spekulace, do jaké oblasti by Opera Software mohl expandovat. Jednou z těch uvěřitelnějších je separace e-mailového klienta z prohlížeče Opera a jeho uvolnění jako samostatného programu. I přes nástup mobilního a webového přístupu k e-mailu by to pro norskou softwarovou firmu mohlo být zajímavé. Zaniká a oslabuje totiž konkurence, na kterou byli uživatelé po léta zvyklí.

Mozilla Thunderbird po předání do rukou komunity působí poněkud bezprizorním dojmem a nikdo vlastně pořádně neví, jestli má ještě nějakou světlou budoucnost. Microsoft pak má ukončit vývoj klienta Windows Live Mail (už aktualizace pro rok 2012 byla čistě jen servisní) a uživatele by zřejmě rád přiměl k přechodu na jeho webový Outlook.com, který nedávno spustil do ostrého provozu.  

linux_sprava_tip

Tím jsou dva mainstreamoví hráči takřka ze hry a příhodnější situace pro uvedení nového e-mailového klienta už asi nebude, než se uživatelé e-mailu mimo korporátní sféru definitivně rozprchnou z desktopu na web a k mobilním zařízením. Ale kdo ví, třeba si jen Opera Software hraje se svými fanoušky a spekulacemi chce dosáhnout také trochy té mediální pozornosti.

Nakonec tedy oním tajemným novým desktopovým produktem bude „jen“ Opera s novým technologickým pozadím. Každopádně mlžení a mlčení, nekonkrétní termíny, klíčové informace vypouštěné jen neoficiální cestou přes blogy na komunitním webu, stahování vlastních videí z YouTube, to už není ta firma, na kterou jsme po léta byli zvyklí. 

Stojí, podle vašeho názoru, Opera Software na prahu nové éry?

Autor článku

Autor je nezávislý novinář a publicista věnující se informatice, elektronice a telekomunikacím. V těchto oborech i podniká, přičemž mezi open source projekty nachází atraktivní řešení pro své zákazníky. Pro Root.cz pravidelně píše od roku 2012.

'; 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'; } }
'; 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 »