Znamená chystaná copyrightová reforma jen další kroky k omezení internetu?

10. 9. 2018
Doba čtení: 7 minut

Sdílet

Směřuje evropské autorské právo ke spravedlivějšímu systému odměňování autorů, nebo k cenzuře, ničení základních principů a utlumení inovací na internetu?

V rámci evropské legislativy se v současné době schyluje k dalšímu projednávání a schvalování tzv. copyrightové reformy, jež vyvolává rozpaky a širokou diskuzi napříč veřejností. Tento článek stručně shrnuje, co je vlastně myšleno copyrightovou reformou, co je jejím nejspornějším obsahem a jaké může mít dopady do světa technologií a autorského práva.

Je až neuvěřitelné, jak rychle se šíří technologie internetu a jakým tempem roste množství obsahu, které je na něm možné najít. Jen pro představu – každou minutu je nahráno 49 380 fotek na Instagram, přehráno na 750 000 písniček na Spotify, zasláno 473 400 zpráv přes Twitter a nahráno až 400 hodin obsahu na službu YouTube. Náplň tohoto ohromného digitálního trhu tvoří díla autorů a spolu s úspěchem tohoto trhu přichází i otázka, jak tyto autory chránit a zároveň nebránit inovacím a rozvoji technologií.

Reforma autorského práva na digitálním trhu spojená s vytvořením vhodných podmínek pro rozvoj digitálních sítí a služeb je jedním ze tří pilířů jednotného digitálního trhu, který Evropská komise představila v dokumentu Strategie jednotného digitálního trhu dne 6. 5. 2016 (dále jen „Strategie“).

Klíčovým instrumentem této reformy autorského práva se stal návrh směrnice Evropského parlamentu a rady o autorském právu na jednotném digitálním trhu (dále jen „Návrh“), který Evropská komise (dále jen „EK“) předložila v září 2016. Její zveřejnění rozpoutalo širokou diskuzi napříč odbornou veřejností i zástupci jednotlivých členských států, kteří opakovaně upozorňovali na některé nebezpečné konsekvence a dopady na digitální trh. I přesto je návrh projednáván před Evropským parlamentem.

Konec linkovací svobody?

Prvním z široce diskutovaných ustanovení Návrhu je jeho čl. 11, kterým EK cílí na zvýšení ochrany vydavatelů tiskových publikací. EK vnímá, že díky přechodu od tištěných k digitálním médiím vznikají pro vydavatele nové výzvy spojené s ochranou online užití jejich tvorby. Cestu k vyřešení tohoto problému vidí EK v uznání vydavatelů online publikací jakožto nositelů práv. V rámci čl. 11 Návrhu je tak založeno nové právo vydavatelů digitálních novinářských publikací rozhodovat o sdělování jejich děl veřejnosti, a to po dobu 20 let od jejich zveřejnění.

Fakticky tak dochází k situaci, kdy vydavatelé budou moci vybírat licenční poplatky za vytvoření tzv. snippets, tj. internetových odkazů doplněných o stručný náhled obsahu, obsaženého v dotyčném článku. Tyto odkazy jsou standardně hojně využívány v rámci sociálních sítí či v rámci specializovaných serverů, tzv. agregátorů zpráv, jako jsou Google News, ITzprávy, Zdroj.cz apod. Vytvořením a zveřejněním takového snippetu bez souhlasu internetového vydavatelství pak dojde k porušení jeho autorských práv.

Zatímco úmysly EK je možné považovat za legitimní a odůvodněné, způsob úpravy vyvolává celou řadu pochybností. Internetové odkazy a snippety jsou jedním ze základních stavebních kamenů internetu a dělají ho pro uživatele tak přitažlivými. Čermák ve své knize velice trefně poznamenává, že internet bez odkazů bychom s určitou nadsázkou mohli přirovnávat k pomalé a nekvalitní televizi. Narušení této funkcionality regulací může vést k dvěma důsledkům – buď dojde k omezení základní funkce internetu, či bude tato regulace ignorovaná, nevymahatelná, a tudíž i zbytečná.

O nevhodnosti tohoto způsobu regulace se můžeme přesvědčit i z historických pokusů toto privilegované právo zakotvit v některých národních řádech. Když se cestou totožné regulace vydalo například Španělsko, nejenže došlo k odlivu některých tak zásadních poskytovatelů služeb, jako je Google News, ale zároveň došlo k poklesu návštěvnosti na serverech vydavatelů, na které bylo prostřednictvím služeb odkazováno.

Omezení linkovací svobody může mít zároveň zásadní dopad na svobodu slova, když uživatelé ztratí možnost mezi sebou jednoduše a efektivně sdílet obsah a ztratí díky tomu i možnost prostřednictvím internetu dohledávat relevantní informace. Omezení se také zásadně může dotknout i celé řady malých start-upů a poskytovatelů z prostředí sociálních sítí a agregátorů zpráv.

S ohledem na výše uvedené je tak třeba být na pozoru, zda navrhovaná regulace skutečně dosáhne účelu, pro který byla připravována. Hrozí zde totiž riziko, zda spíše než zajištění ochrany tiskovým vydavatelstvím nezpůsobí disbalanci na digitálním trhu, vedoucí k omezení fungování internetu, konci některých zásadních služeb, a tím i k citelnému poškození vydavatelů.

Poskytovatelé služeb pod drobnohledem

Druhý a neméně závažný institut obsahuje čl. 13 Návrhu, zabývající se užitím chráněného obsahu poskytovateli služeb informační společnosti (internet service providers, dále také jen „ISP“). EK tímto ustanovením reaguje na své tvrzení, že online služby, prostřednictvím kterých uživatelé mohou na internet nahrávat obsah, se stávají hlavním zdrojem přístupu k autorskoprávně chráněnému obsahu.

EK se svou regulací snaží cílit na tzv. „value gap“. Tento je třeba chápat jako rozdíl mezi hodnotou, kterou představuje autorskoprávní obsah pro jeho uživatele, a hodnotou a výší protiplnění, které za ní obdrží autoři. Míra value gapu se dle autorů tohoto pojmu liší napříč službami – zatímco value gap v případě služeb poskytovatelů obsahu, jako jsou Spotify či Apple Music, je relativně nízká, v případě ISP, kteří umožňují ukládat a sdělovat uživatelský obsah, je významně vyšší.

Z tohoto důvodu přichází EK v čl. 13 Návrhu s ustanovením, které ukládá ISP, kteří ukládají velké množství děl a jiných předmětů ochrany jejich uživateli a zpřístupňují je veřejnosti, přijmout konkrétní opatření zabraňující, aby v rámci jejich služeb byla dostupná díla nebo jiný předmět ochrany. Návrh za takové opatření považuje například technologii rozpoznávání obsahu. V konečném důsledku může navrhovaná povinnost vést k tomu, že dotčené platformy budou muset filtrovat a monitorovat chování svých uživatelů a jejich dat pod záštitou ochrany autorských práv.

Pro velice vágní vymezení povinných subjektů (EK nedává žádné vodítko, co je třeba považovat za „velké množství děl“) bude mít ustanovení praktický dopad pravděpodobně především na služby, jako jsou sociální sítě (Facebook, Twitter, Instagram), úložiště dat (Dropbox, OneDrive, Google Drive), služby umožňující sdílení audiovizuálního obsahu (YouTube, Vimeo), ale i další významné služby (blogy, Wikipedia apod.). Tyto subjekty budou muset dostát výše uvedeným povinnostem. Je velice pravděpodobné, že rozsah služeb, kterých se úprava bude dotýkat, bude v budoucnu ze strany EK ještě dále konkretizována a prohlubována.

Čl. 13 Návrhu vzbudil asi nejvášnivější diskuze napříč odbornou veřejností, a to z celé řady důvodů. V první řadě povinnost zavedení generálního dohledu nad daty ukládanými a přenášenými ISP je zásadním odklonem současného právního stavu, kdy předpisy, stejně jako rozhodovací praxe soudů, zapovídá vůči ISP takovou povinnost ukládat. Úprava jde tak koncepčně proti současnému právnímu statu quo, stejně jako proti myšlenkám, na kterých byl vystaven.

Odborná veřejnost však upozorňuje i na další aspekty. V první řadě povinnost filtrování obsahu není a nemůže být jednoduchým řešením složitého problému. Je třeba vnímat, že jak automatické filtrační mechanismy, tak filtrační mechanismy manuální (prováděné za pomocí lidského faktoru) jsou značně nákladné a v celé řadě případů nefunkční.

Automatické filtrační mechanismy je možné užít jen pro některé typy uživatelského obsahu – zatímco vyhledávání kopie autorského textu v rámci blogů může vykazovat vyšší míru úspěšnosti, kontrola úložiště zálohujícího šifrovaný obsah je významně obtížnější až nemožná. Nadto automatické filtrační mechanismy nemusí spolehlivě rozlišovat mezi protiprávně nahraným obsahem a obsahem nahraným oprávněně (na základě licence, v rozsahu citace, parodie, fair use apod.). Tyto mechanismy je navíc po odhalení způsobu jejich fungování možné obelstít a obejít a jejich efektivita postupem času významně klesá.

Je zde proto na místě obava, zda zavedení povinnosti filtrovat obsah nebude především zásadní administrativní a ekonomickou zátěží. Ta následně povede k obecnému, trvalému a systematickému monitorování chování uživatelů, stejně jako ke vzniku podstatné překážky pro vstup na trh pro všechny menší a inovativní subjekty.

CIF25_SE_terc

Co říci závěrem

Je nepochybné, že autorské právo by se mělo přizpůsobovat výzvám současné doby a v prostředí tak relativně mladého a vyvíjejícího se média, jakým je internet, by mělo vytvářet prostor pro nové inovace a spravedlivé odměňování kreativity. Současný návrh regulace však spíše než vymizení některých patologických jevů vytváří nové administrativní a ekonomické překážky. Služby se budou velice pravděpodobně spíše oklešťovat, unifikovat a přizpůsobovat regulaci tak, aby jí byly co nejméně postiženy, což nenávratně povede k menší diversifikaci trhu, utlumení inovací a snížení komfortu uživatelů internetu.

Jak velice dobře uvádí Julia Reda na svém blogu, možnost využívat nová média bez neustálého narážení na právní překážky a nejistoty je nejen legitimním zájmem, ale i naprostou nezbytností. V opačném případě bychom tu po utlumení inovací a odlivu subjektů z evropského digitálního trhu sice mohli mít digitální trh, který bude v souladu s vizí EK jednotný, ale také naprosto prázdný. Více se snad dozvíme 12. září tohoto roku, kdy se bude Evropský parlament Návrhem znovu zabývat.

Autor článku

Autor je advokátem v Ambruz & Dark Deloitte Legal a také členem České advokátní komory. 

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