Příkazový řádek – přítel nejvěrnější

10. 4. 2001
Doba čtení: 6 minut

Sdílet

Ilustrační obrázek
Autor: Depositphotos – stori
Ilustrační obrázek
Moderní interprety příkazů, jako je bash či tcsh, poskytují vynikající možnosti, jak si usnadnit život. Já osobně jsem si na ně zvykl natolik, že necítím potřebu používat Midnight Commander. A když jsem nucen čas od času sáhnout po DOSovském COMMAND.COM, trpím jako zvíře. V dnešním článku se vám pokusím poskytnout pár tipů, jak si zpříjmenit své soužití s interpretem příkazů.

Historie

To, že si interpret příkazů uchovává jejich historii, dnes bereme jako samozřejmost. Párkrát zmáčkneme kurzor nahoru, dokud se neobjeví hledaný příkaz, upravíme, odešleme, chrochtáme blahem.

Já se však hodlám vrátit do dávnější minulosti, kdy špičkou mezi interprety byl csh. Ten už měl historii příkazů, ovšem zcela neinteraktivní. Odkazovali jste se na ni speciálními sekvencemi začínajícími vykřičníkem. Například !! znamenalo „zopakuj poslední příkaz“, !19 zopakovalo devatenáctý provedený příkaz a !-5 pátý od konce.

Proč vás obtěžuji podivnými senilními vzpomínkami? Protože některé z těchto konstrukcí jsou proklatě užitečné. Například !řetězec se vrací v historii tak dlouho, až narazí na příkaz začínající řetězcem. Ten pak provede. !gcc tedy zopakuje váš poslední překlad. Chcete-li zopakovat příkaz, který leží hlouběji v historii, je to rychlejší, než ťapat k němu kurzorem.

Čas od času se hodí i konstrukce !?řetězec?, která se vrací v historii a hledá provedený příkaz, který obsahuje zadaný řetězec. Hledá jej v celém řádku, nikoli jen na začátku.

Zmíněné odkazy na historii můžete používat jako součást řádku a doplňovat k nim další prvky. Například !gcc -O2 zopakuje poslední překlad a přidá k němu volbu „-O2“.

Moderní interprety nabízejí i interaktivní verzi prohledávání historie.

bash
Implicitně nemá hledání mapováno na žádnou klávesu. Doporučuji k tomuto účelu použít Ctrl-P a Ctrl-N, které kopírují funkce šipek nahoru a dolů a nebývají tudíž potřeba. Do souboru ~/.inputrc přidejte řádky:
C-p: history-search-backward
C-n: history-search-forward

Změna se projeví až v nově spuštěném interpretu.

tcsh
Implicitně mapuje hledání v historii na klávesové sekvence Ctrl-[ p a Ctrl-[ n. Pokud byste je chtěli přemapovat na výše zmiňované Ctrl-P a Ctrl-N, použijte příkazy:
bindkey ^P history-search-backward
bindkey ^N history-search-forward

Chcete-li toto chování používat stále, vložte zmíněné příkazy do souboru ~/.tcshrc (případně ~/.cshrc)

Když po provedení zmiňovaných úprav napíšete na příkazový řádek gcc a stisknete Ctrl-P, poskočí interpret v historii na nejbližší předchozí příkaz začíznající „gcc“. Klávesami Ctrl-P a Ctrl-N pak můžete poskakovat mezi jednotlivými příkazy s tímto začátkem.

Další vychytávkou staré gardy je konstrukce ^raz^dva, která vezme předchozí příkaz, vyhledá v něm první výskyt řetězce „raz“ a nahradí jej řetězcem „dva“. Takto upravený příkaz pak provede. Například když chcete provést

program soubor1.dat
program soubor2.dat

zadejte

program soubor1.dat
^1^2

Je to rychlejší než měnit jedničku na dvojku interaktivně pomocí editačních kláves.

Poslední historizující konstrukcí, o které se zmíním, je používání parametrů z historie. Nejčastější jsou odkazy na parametry předchozího příkazu:

Tabulka č. 112
!* všechny parametry
!^ první parametr
!$ poslední parametr

To lze využít například při opatrném mazání. Nejprve si příkazem ls nechám vypsat kandidáty ke smazání

ls *.bak *.old *.tmp

a pokud jsem se seznamem souborů spokojen, nechám totéž vymazat

rm !*

Tyto „historické“ parametry vám občas přijdou k duhu i při vytváření aliasů. Úplně stejně se totiž odkazujete v definici aliasu na parametry, které uživatel zadá při jeho použití. Zde se jedná o takzvanou budoucí historii ;-)

S odkazy na parametry lze činit řadu kouzel (včetně vytahování jejich částí, odřezávání přípon a podobně). To však při interaktivní práci upotřebíte jen vzácně. Častěji budete tyto kejkle potřebovat při vytváření skriptů, ovšem v takovém případě byste neměli být líní podívat se do manuálové stránky odpovídajícího interpretu.

Doplňování

Doplňování názvů příkazů, souborů a dalších komponent dnes bereme jako samozřejmost. Napíši prvních několik znaků, stisknu tabulátor a interpret dokončí slovo za mne.

Pokud je začátek jednoznačný. Chování při nejednoznačnosti je do značné míry ovlivnitelné. Přiznám se, že implicitní nastavení mi příliš nevyhovuje. Chtěl bych, abych při nejednoznačnosti okamžitě dostal nabídku jmen, která lze získat z daného začátku. Podívejme se, jak to zařídit.

bash
Do souboru ~/.inputrc přidejte řádek
set show-all-if-ambiguous on

Nyní při nejednoznačnosti místo obvyklého zatroubení dostanete nabídku dostupných jmen, což je přesně to, co člověk zpravidla potřebuje.

Seznam nabízených souborů můžete omezit pomocí proměnné prostředí FIGNORE. Obsahuje dvojtečkami oddělovaný seznam přípon, které mají být při doplňování ignorovány. Například


FIGNORE='.o:~:.bak'
export FIGNORE

zajistí, že při doplňování si interpret nebude všímat souborů, jejichž jména končí „.o“, „~“ či „.bak“. Existuje i proměnná GLOBIGNORE, kde můžete zadat jména ignorovaných souborů pomocí žolíkových znaků. Ovšem v reálném životě přípony zpravidla postačí. Má-li mít nastavení trvalý účinek, musíte je provést ve startovacím souboru (~/.bash_profile, ~/.bash_login či ~/.profile).

tcsh
Zde je třeba nastavit proměnnou interpretu
set autolist

Lze to udělat interaktivně, pro trvalý účinek vložte uvedený příkaz do souboru ~/.tcshrc.

Také tcsh umožňuje definovat přípony, které budou při doplňování ignorovány. K tomuto účelu zde slouží proměnná interpretu fignore. Stejného účinku jako výše bychom dosáhli příkazem


set fignore = (.o \~ .bak)

Příkaz patří do souboru ~/.tcshrc.

Interprety dovedou doplňovat ledacos:

bitcoin_smenarna

  • jméno příkazu (u prvního slova na řádku)
  • jméno souboru/adresáře (u dalších slov na řádku)
  • jméno uživatele (začíná-li slovo znakem „~“)
  • jméno proměnné (začíná-li slovo znakem „$“)
  • jméno počítače (začíná-li slovo znakem „@“)

Pro kutily je k dispozici příkaz complete, pomocí kterého mohou s doplňováním vysloveně čarovat. Jeho prostřednictvím lze definovat, jak má vypadat seznam možností, z nichž se bude vybírat doplňovaný řetězec. Příkaz se sice u obou interpretů jmenuje stejně, jeho tvar se však zásadně liší.

bash
bash nabízí příkaz complete až v nejnovějších verzích (verze 2.04 jej zcela jistě má). Má podobu

complete   konstrukce_sez­namu   příkaz


kde konstrukce_seznamu určuje, jak se bude vytvářet seznam kandidátů na doplnění pro daný příkaz. Významnou roli v něm zpravidla hraje -A akce, která vytvoří základní seznam. Dostupných akcí je zhruba dvacet, mezi nejběžnější patří file (seznam souborů), directory (seznam adresářů) či command (seznam příkazů).

Na vzniklý seznam lze pak nasadit filtr -X  výraz, kterým omezíte sortiment možností. Výrazem je běžný žolíkový znak a filtr vyřadí všechna jména, která mu vyhoví. Pokud výraz začíná vykřičníkem, vyhovující jména jsou naopak ponechána a vyřadí se vše ostatní.

Špetka ilustračních příkladů:

complete -A directory cd
zařídí, že příkazu cd budou v prvním parametru doplňovány jen adresáře.

complete -A command man
zapne doplňování jmen příkazů v parametrech příkazu man.

complete -A file -X ‚!*.ps‘ ghostview
si bude při doplňování parametrů příkazu ghostview všímat jen souborů s příponou „.ps“.

tcsh
Tento interpret nabízí complete již dost dlouho, takže je zjevné, kdo od koho opisoval ;-) Má odpudivější syntaxi, větší schopnosti a především je v manuálové stránce mnohem lépe popsán (včetně pokročilejších příkladů, které u bash zcela chybí). Základní tvar je

complete   příkaz   slovo/vzor/sez­nam/


Slovo určuje, které slovo (vůči aktuálnímu) se doplňuje. Nejběžnějšími hodnotami jsou c (aktuální), n (následující) a p (slovo na dané pozici). Vzor pak stanoví vzor či pozici, kterému musí aktuální slovo vyhovět, aby došlo k aktivaci pravidla. Můžete tedy vytvořit několik pravidel pro tentýž příkaz.

Seznam definuje seznam hodnot, které budou brány v úvahu při doplňování. Nejčastěji používané hodnoty: f (jména souborů), d (adresáře), c (příkazy). Můžete sem také zapsat příkaz uzavřený do obrácených apostrofů a jeho výstup pak bude interpretován jako seznam možností. Za seznam můžete ještě připojit dvojtečku a žolíkový výraz. Ten pak ponechá v seznamu jen jména, která mu vyhovují.

Příklady:

complete cd ‚p/1/d/‘
zajistí, že příkazu cd budou doplňovány jen adresáře.

complete man ‚p/*/c/‘
doplňuje příkazu man názvy příkazů.

complete ghostview ‚p/*/f:*.ps/‘
doplňuje v parametrech ghostview jen soubory s příponou „.ps“.

complete kill ‚p/*/ ps | awk \{print\ \$1\}/‘
doplňuje příkazu kill čísla aktivních procesů.

complete find ‚n/-user/u/‘
doplňuje příkazu find v parametru následujícím za „-user“ jen jména uživatelů.


A to je pro dnešek vše. Příště se podíváme na opravování překlepů, ukážeme si několik triků pro práci s adresáři a také si povíme něco málo o nastavování promptu.

Autor článku

Pavel Satrapa působí na Ústavu nových technologií a aplikované informatiky na Technické univerzitě v Liberci, píše knihy a motá se kolem tuzemské akademické sítě CESNET.

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