Zprávy v datových schránkách se zvětší jen na 100 MB místo na původně plánovaný 1 GB

10. 10. 2023
Doba čtení: 11 minut

Sdílet

Autor: Depositphotos
Agentura DIA již připravila novelu prováděcí vyhlášky, která by k 1. 1. 2024 měla zvětšit maximální velikost datových zpráv a zavést nové formáty příloh. Nechystá se ale využít příležitost k opravě dřívějších chyb, naopak se chystá k nim přidat další, nové chyby.

Po velkém třesku na přelomu loňského a letošního bylo kolem datových schránek delší dobu ticho. Jen drobně narušené zmínkou o dalším odkladu již dříve zveřejněného záměru: zvětšit maximální velikost datové zprávy a zavést nové formáty toho, co je možné vkládat do datových zpráv jako jejich přílohy. Nově byly změny odloženy až na přelom současného a nového roku, neboli k 1. 1. 2024.

Jaký je současný stav a co se má změnit?  

Dnes je pro celé datové zprávy, tedy včetně všech příloh, maximem 20 MB. Existují ale privilegované datové schránky (tzv. další DS OVM, zřizované na žádost), do kterých lze zasílat i datové zprávy do maximální velikosti 50 MB. 

To ale nemusí v některých případech stačit – a tak se již dříve zrodil záměr zvětšit maximální velikost až na 1 GB. S tím, že půjde o tzv. velkoobjemové zprávy (VoDZ), kterými mohou být jak veřejnoprávní datové zprávy, tak i ty soukromoprávní (poštovní).

Současně mělo dojít k rozšíření formátů možných příloh datových zpráv o „kontejnerové“ formáty ZIP a ASiC, které se dosud do datových zpráv vkládat nedají.

Jak se postupně odkládalo a měnilo

První zmínka o popisovaném záměru zazněla již na jaře roku 2021. V testovacím prostředí byly změny nasazeny již v roce 2022 a v ostrém (produkčním) prostředí se původně měly objevit již počátkem toku 2023. Jenže podmínkou bylo připravit návrh změny prováděcí vyhlášky (č. 194/2009 Sb.), ve které je vše zakotveno. Což se napoprvé nestihlo, a tak došlo k prvnímu odkladu celého záměru – na polovinu roku 2023.

Potřebný legislativní návrh na novelizaci prováděcí vyhlášky, ještě z dílny MV ČR, se objevil v eKlepu až počátkem roku 2023 a prošel i standardním připomínkovým řízením. V něm zazněly dvě hlavní skupiny připomínek: jedna argumentovala tím, že účinnost k 1. 7. 2023 nedává příjemcům dost času na to, aby své systémy stihli upravit na novou maximální velikost datových zpráv. Druhá poukazovala na to, že 1 GB je moc a že elektronické spisové služby na to nejsou připraveny:

Domníváme se, že změna z 20 MB na 1 GB je příliš velká. eSSl nejsou v současné době na takovou změnu přizpůsobené.

Nakonec byl přijat „kompromis“: změny se odloží o půl roku (k 1. 1. 2024) a z 1 GB se sleví na 100 MB. Aby bylo dost času přizpůsobit se i takto snížené laťce:

Účinnost vyhlášky bude odložena k datu 1. 1. 2024, které se jeví po projednání s dotčenými resorty a po modifikaci původního návrhu k implementaci dostatečné.

Takovéto změny v návrhu novely si ale vyžádaly její úplně nový návrh, nyní již z dílny agentury DIA. Ten se ve veřejném eKlepu nedávno (20. září) skutečně objevil. Pojďme se na něj podívat podrobněji.

Co všechno se má změnit?

Nový návrh, formálně: „Návrh vyhlášky, kterou se mění vyhláška č. 194/2009 Sb., o stanovení podrobností užívání a provozování informačního systému datových schránek, ve znění pozdějších předpisů“ skutečně počítá se zvětšením maximální velikosti datových zpráv jen na 100 MB místo původního 1 GB.

Jde přitom o velikost datových zpráv ve smyslu toho celku, který se skutečně přenáší mezi datovými schránkami, má (při stahování) formát ZFO a chová se jako přenosový kontejner, ve kterém je umístěna jedna, nebo více příloh. 

Jak na datovku: Mizení zpráv, fikce i časová razítka. Nejčastější mýty o datových schránkách Přečtěte si také:

Jak na datovku: Mizení zpráv, fikce i časová razítka. Nejčastější mýty o datových schránkách

Je bohužel nutné to takto zdůraznit, protože samotná vyhláška (i její novela) používají pojem „datová zpráva“ jak v tomto smyslu, tak i ve smyslu příloh, vkládaných do skutečně přenášených datových zpráv (viz dále). Nejde tedy o maximální velikost jednotlivých příloh, ale o souhrnnou velikost všech příloh v jedné zprávě (a příslušné obálky).

Další změnou oproti původnímu návrhu je rozšíření výčtu nově přidávaných formátů příloh datových zpráv (nikoli datových zpráv samotných). Původně bylo navrhováno přidat jen dva „kontejnerové“ formáty, a to ZIP a ASiC.

Z připomínkového řízení k předchozímu návrhu vzešel požadavek na přidání formátu JSON. Byl akceptován a kromě něj mají přibýt i formáty MPEG-4 (audio i video) a také formát HEIF (High Efficiency Image File Format), který je v zásadě také kontejnerovým formátem. Nicméně novela jej za kontejnerový formát nepovažuje.

Kontejnery ano, ale…

To, zda prováděcí vyhláška považuje určitý formát přílohy jako kontejnerový, je relevantní kvůli dalším požadavkům, které jsou na kontejnerové formáty kladené. Tím hlavním je to, aby do kontejneru „bylo vidět“ a systém datových schránek se dostal k jeho obsahu a mohl kontrolovat jeho strukturu, počet objektů (souborů i adresářů) i jejich formát a detekovat případný malware. Kontejnery proto nesmí být zašifrované.

Po samotném obsahu kontejneru se pak požaduje, aby obsahoval alespoň jeden soubor v některém z „nekontejnerových“ formátů, explicitně uvedených ve vyhlášce, a naopak neobsahoval žádný soubor jiného formátu (než jsou ty „nekontejnerové“, uvedené přímo ve vyhlášce). 

Není tedy přípustné ani vnořování kontejnerů (vkládání jednoho kontejneru do druhého). Obsahem kontejneru navíc nesmí být více než 1000 souborů (a adresářů), maximální hloubka vnoření adresářů je 4 a po dekomprimaci nesmí mít obsah kontejneru více než 3 GB.  

Více možností pro vyloučení z přepravy

Další změnou, která souvisí se zabezpečením systému datových schránek, je možnost nepřijmout datovou zprávu k odeslání v případě hrozícího přetížení systému:

Cílem navrhované změny je tak poskytnout správci, resp. provozovateli ISDS funkční nástroj, jak adekvátně předcházet a reagovat na již vzniklé ohrožení bezpečnosti, dostupnosti a funkčnosti ISDS a jiných informačních systémů veřejné správy ze strany osob, které využívají datovou schránku k tzv. denial-of-service (DoS) útokům.

Konkrétní formulace je nejspíše záměrně velmi obecná a zahrnuje v sobě i detekci malwaru, který naopak jako samostatný bod mohl vypadnout.

Autor: Jiří Peterka

Zajímavé je, že celé ustanovení je formulováno s ohledem na správce datových schránek, kterým je dnes agentura DIA. Jen té tak vyhláška dává popisovaná práva nepřijmout k odeslání konkrétní datové zprávy. Ve skutečnosti by toto právo asi potřeboval spíše provozovatel celého systému, kterým je Česká pošta.

Tím už se dostáváme k problematickým místům současné vyhlášky i její nově navrhované novely.

Přípony místo formátů

Přetrvávajícím problémem je, že stávající vyhláška i její novela specifikují přípustné formáty příloh nikoli jako takové, např. skrze jejich MIME typy, či alespoň odkazy na příslušné normy a standardy, nýbrž výčtem přípustných přípon souborů. To ale není jednoznačné: pro stejný formát se může používat více různých přípon, třeba i v závislosti na konkrétní systémové platformě, a někdy se stejné přípony používají pro různé formáty.

Příkladem mohou být videoformáty MPEG. Ve stávající verzi vyhlášky jsou přípustné formáty MPEG-1 a MPEG-2, ale určeny jsou jen dvěma možnými příponami: mpeg1 a mpeg2. Takže když bude mít soubor v takovémto formátu s příponu jen mpg (např. kvůli omezení délky přípony jen na tři písmena), již to není přípustný formát přílohy? A pro možnost přenosu je třeba změnit jeho příponu?

Tento konkrétní problém u formátů MPEG-1 a MPEG-2 bude novela částečně řešit připuštěním dalších dvou „zkrácených“ přípon: mpg a mpeg.

Autor: Jiří Peterka

Přitom přípony mpg a mpeg jsou fakticky přípustné i dnes, a tak jde spíše o „dorovnání“ právní úpravy ke skutečnému stavu.

Autor: Jiří Peterka

Nicméně samotný problém zůstává a bude pokračovat. Třeba u nově zaváděného formátu HEIF, pro který se také používá více různých přípon, podle toho, co je jeho obsahem.

Autor: Jiří Peterka

Co třeba zkrácená třípísmenná přípona hif? Nebo proč zde nejsou uvedeny přípony heifs a heics, používané pro HEIF kontejnery se sekvencemi obrázků (místo s jednotlivými obrázky)?

Není datová zpráva jako její příloha

Na předchozím obrázku si můžete všimnout dalšího kuriózního problému: zatímco v reálném světě všechny „datové zprávy dodávané do datové schránky“ mají pevný formát (a po svém stažení příponu zfo), vyhláška říká, že „datové zprávy, dodávané do datové schránky“ mohou mít různé formáty, a vyjmenovává ty, které to mohou být, resp. které jsou přípustné. Nejsou to přitom jenom ty z předchozího obrázku, ale i celá řada dalších od PDF přes XML, DOC(X) až třeba po nově přidávané kontejnerové formáty ZIP a ASiC.

Pokud nad tím kroutíte hlavou, pak vězte, že chyba není tak úplně na straně autorů dosavadní vyhlášky. Chyba se stala už v zákoně (č. 300/2008 Sb.), který původně dával Ministerstvu vnitra zmocnění k vydání pouze takové vyhlášky, která by stanovovala přípustné formáty datové zprávy. Nikoli přípustné formáty příloh datové zprávy, k tom vnitro zmocněno nebylo.

Autor: Jiří Peterka

A tak se to vyřešilo „jednoduše“: vyhláška byla vydána tak, aby sice specifikovala možné formáty (ve skutečnosti přípony) příloh, ale kvůli nesprávnému zmocnění je musela prezentovat jako možné formáty samotných datových zpráv. Naopak o formátu „skutečné“ datové zprávy se ve vyhlášce nic nedočtete.

Časem naštěstí došlo k úpravě zmocnění přímo v zákoně č. 300/2008 Sb., a to k 1. 2. 2022, skrze zákon DEPO (zákon č. 261/2021 Sb.). Ten rozšířil zmocnění tak, aby prováděcí vyhláška mohla specifikovat nejenom formát datové zprávy, ale také formát jejích příloh. V mezidobí (k 1. 4. 2023) pak celé zmocnění přešlo z vnitra na novou agenturu DIA.

Autor: Jiří Peterka

Mohlo se tedy zdát, že je jen otázkou času, kdy dojde k úpravě nesmyslného znění vyhlášky, aby se věci již daly označovat pravými jmény. Aby výčet přípustných formátů mohl být prezentován správně jako výčet přípustných formátů příloh datových zpráv, a nikoli datových zpráv samotných.

Ideální příležitostí k tomu byla příprava novely celé prováděcí vyhlášky. Vlastně již té první zde popisované, z počátku letošního roku. Ta ale příležitosti nevyužila a setrvala na dosavadním přístupu „říkám sice A, ale myslím tím B“.

Bohužel ani nejnovější verze návrhu novely šanci k nápravě nevyužila a nadále setrvává v přístupu „říkám A, myslím B“. Dokonce by se dalo říci, že jej pozvedává na novou, ještě vyšší úroveň dokonalosti. Třeba když vznáší své požadavky na kontejnery (vkládané jako přílohy do datové zprávy), ale mluví o těchto kontejnerech jako o datové zprávě samotné a chce, aby její obsah nebyl zašifrovaný. 

Ve skutečnosti má na mysli to, aby nebyl zašifrován obsah kontejneru, a systém datových schránek tak mohl procházet jeho vnitřní strukturu a kontrolovat, zda jeho obsah splňuje jeho další požadavky (počet souborů a adresářů, hloubku vnoření, absenci škodlivého kódu).

Autor: Jiří Peterka

Nebo když uvádí podmínku „datovou zprávu netvoří soubor v jiném formátu než ve formátu uvedeném v bodu I nebo II“ (což jsou nekontejnerové formáty). Má tím ale na mysli to, že obsahem kontejneru mohou být jen takové soubory, které by mohly být do datové zprávy vloženy jako přílohy přímo (a ne jako obsah kontejneru ZIP či ASiC). Přesněji: takové, které jsou ve vyhlášce vyjmenovány jako přípustné. V tom je totiž rozdíl, viz dále.

ASiC kontejner nepůjde podepsat

Jak jsme si již uvedli, v návrhu vyhlášky (konkrétně v bodě c) části V, viz předchozí obrázek) se explicitně říká, že obsahem kontejneru nesmí být soubor žádného formátu, který není ve vyhlášce uveden (mezi těmi nekontejnerovými).

To je ale problém: tvůrci vyhlášky, a to již té první a současné, stejně jako autoři nynější novely, totiž zapomněli na existenci externích elektronických podpisů a neuvedli je mezi přípustnými formáty příloh datových zpráv. A tak se to již kdysi dávno „překlenulo“ kreativním právním výkladem ve smyslu: zákonodárce přeci nechtěl zakázat externí podpisy, a tak musí být přípustné i jejich formáty.

Autor: Jiří Peterka

Dodnes tak v Provozním řádu datových schránek najdeme, že formáty externích podpisů (uvedené na obrázku) jsou přípustnými formáty příloh datových zpráv, a to „z rozhodnutí správce“ (kterým bylo původně vnitro, dnes DIA).

Jenže: bude takovýto kreativní výklad možný i po tom, co prováděcí vyhláška „přitvrdí“ a řekne explicitně, že (byť jen v kontejneru) nesmí být nic v takovém formátu, který není ve vyhlášce uveden?

I když se tento explicitně formulovaný požadavek fakticky týká jen obsahu nově přípustných kontejnerů, i tak je to velký problém, a to pro kontejnery ASiC. Ty jsou totiž v zásadě řešením pro „zabalení“ podepsaného obsahu (kterým může být více jednotlivých souborů) a jeho externích podpisů do jednoho celku, navíc s popisem formátů a vzájemných vazeb (co je čím podepsáno atd.).

Standardy přitom počítají se dvěma hlavními druhy ASiC kontejnerů, podle toho, zda se v nich nachází externí podpisy ve formátu XAdES, nebo CAdES (a případně ještě samostatná časová razítka). Externí podpisy ve formátech XAdES jsou soubory s příponou .xml (a jsou to vlastně XML data), a jsou tedy mezi přípustnými formáty toho, co datové schránky připouští v ASiC kontejneru.

Jenže v případě CAdES podpisů uvnitř ASiC kontejnerů jde typicky o soubory s příponou p7s, které ve výčtu přípustných formátů ve vyhlášce nejsou – a jsou pouze mezi těmi, které jsou přípustné díky kreativnímu právnímu výkladu, viz výše.

Bude zajímavou otázkou, zda po přijetí popisované novely prováděcí vyhlášky ASiC kontejnery s CAdES podpisy projdou skrze datové schránky. Zda správce setrvá na svém výkladu o přípustnosti formátů externích podpisů (a časových razítek) i při novém znění vyhlášky.

CIF25_SE_terc

A ještě jeden problém: pokud si u ASiC kontejneru necháte prodloužit jeho digitální kontinuitu (provést „uchování“, např. kvalifikovanou službou pro uchovávání), přibudou vám v ASiC kontejneru další soubory. Některé mají formát, resp. příponu, se kterým se v právním výkladu počítá (p7s, cer, tst). Ale jedním z nich budou i revokační informace, buď v podobě CRL seznamu (nejspíše s příponou crl), nebo v podobě odpovědi OCSP serveru (s příponou ors). A s těmi nepočítá ani onen kreativní právní výklad (původně z roku 2010).

Pak už nejspíše neprojde ani takto „uchovaný“ ASiC kontejner s XAdES podpisy. Například takový, jaký produkují notáři při elektronické legalizaci podpisů.

  • 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

Autor byl dlouho nezávislým konzultantem a publicistou, 10 let byl členem Rady ČTÚ. 35 let působil také jako pedagog na MFF UK v Praze.

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