Začínám podnikat. Jaké appky se mi hodí pro tvorbu kampaně?

20. 3. 2025
Doba čtení: 8 minut

Sdílet

Mladý muž drží telefon v ruce před obrazovkou svého počítače.
Autor: Depositphotos
Ilustrační obrázek
Byznys začínajícího podnikatele musí být především vidět. Dnešní marketing se přesouvá do online prostředí. Drobným podnikatelům se tak budou hodit šikovné aplikace, které pomůžou s tvorbou kampaní.

Probírat se hromadou aplikací, které by mohly pomoci s tvorbou kampaní, může být pro drobného podnikatele procházkou hustou džunglí. V tomto článku proto představujeme ty, které se mohou hodit, a vyjmenováváme jejich výhody a nevýhody.

Co se dozvíte v článku
  1. Jak na tvorbu kampaně?
  2. Pamatujte na autenticitu
  3. Tipy na šikovné aplikace
  4. Příklad návrhu kampaně

Jak na tvorbu kampaně?

Vizuální kampaň je nutné nejdříve vymyslet. Dobré je pamatovat na fotky i videa, především ta krátká. Pro rychlejší kreativitu je dobré využít ty aplikace, které pomohou hlavně zkrátit čas.

Rozhodně není dobrý nápad generovat vizuály, tedy fotky a videa, pomocí AI. Sociální sítě, na které je dobré se zaměřit, takový obsah automaticky rozpoznají a snižují pak takovým postům organický dosah, tedy příspěvek vidí méně lidí.

Pamatujte na autenticitu

Dnešním trendem je autenticita, do které je nutné promítnout emoce. Pokud mám malou pekárnu, nestačí jen vyfotit samotný produkt. Do fotek by se měly promítat emoce, klidně i ty negativní. Pokud se várka chlebů ráno nepovedla, může být první fotkou smutný výraz pekaře, jak drží v ruce spálený chleba, aby potom následovala další fotka šťastného výrazu, kdy se další várka povedla a je připravena k prodeji.

Podnikatelé by se neměli bát ukázat také své zázemí. Případní zákazníci tak uvidí pohled do míst, která běžně neznají. V případě malé kavárny není na škodu ukázat, kde se zrnková káva skladuje a jak probíhá výroba zákusků, které lze v kavárně zakoupit. Dnešní kampaně nejsou tak o samotném produktu nebo službě, ale o celém procesu, kterým by podnikatel měl svého zákazníka provést.

Aby byly podobné kampaně co nejkreativnější, mohou pomoci právě níže uvedené aplikace, které celý proces produkce zjednoduší.

Tipy na šikovné aplikace

Gemini a ChatGPT

Obě aplikace využívají umělou inteligenci. Jsou si velmi podobné, přesto mohou obě generovat odlišné výsledky. V našem případě se hodí pouze pro návrh tvorby samotné kampaně. Jak už bylo řečeno, pro výrobu samotných vizuálů se nehodí. Na konci článku jsou uvedeny návrhy obou aplikací pro tvorbu kampaně malého pekaře. Co je pro podnikatele srozumitelnější, můžete porovnat sami.

V základní verzi jsou obě aplikace zdarma. ChatGPT dnes ani nevyžaduje při základním dotazu registraci, respektive přihlášení.

Canva

Canva je velmi oblíbený grafický nástroj, protože dokáže pomoci i těm, kteří nemají pro vizuální stránku žádný cit. Ovládání je jednoduché a intuitivní a obsahuje velké množství šablon, které usnadní práci s grafickým návrhem.

V Canvě lze dobře vytvářet vizuály, upravovat fotky, a dokonce vytvářet videa. Tvorba videí je v Canvě trochu kostrbatá, přesto pro začátky a krátká videa stačí. V základní verzi je zdarma, ale je limitována konkrétními prvky, které lze při tvorbě využít. O Canvě jsme na Podnikateli již psali a přinesli také velký seriál návodů.

Darkroom

Aplikace Darkroom se hodí, pokud je nutné publikovaným fotkám a videím přidat nádech barevných filtrů. Aplikace také dokáže jednotlivé vizuály snadno ořezávat při zachování kvality souboru a přidávat k fotkám fotorámečky, které se opět vracejí na scénu.

Je oblíbená především díky svému „cinematic“ filtru, který dá publikovaným fotkám i videím profesionální nádech. Její velkou nevýhodou je, že ji mohou používat pouze uživatelé s „jablečným“ operačním systémem, tedy typicky uživatelé iPhonu, MacBooků, iPadů. Na druhou stranu lze její prostředí používat napříč všemi zařízeními. V základu je opět zdarma, ale nejžádanější filtry jsou už zahrnuty do předplatného. To se dá vyzkoušet zdarma po dobu 7 dnů.

InShot

InShot je grafickou aplikací pro úpravu fotek a videí. Pokud nepotřebujeme výhody Canvy, stačí stáhnout po této aplikaci. Poradí si také se střihem krátkých videí. Obsahuje nástroje umělé inteligence, které upravovaným fotkám a videím dají nový směr.

Určena je primárně pro chytré telefony. Dostupná je jak pro iPhone, tak i telefony s operačním systémem Android. Aplikaci lze využít také na tabletech. I když obsahuje předplatné, lze si zakoupit doživotní licenci, kterou je možné v rámci akcí získat za velmi výhodnou cenu. Stejně jako Darkroom obsahuje filtry pro vylepšení upravovaných fotek a videí. Její nevýhodou je, že je určena pouze pro mobilní zařízení, což některým vyhovovat nemusí. V tom případě je lepší sáhnout po Canvě, kterou lze používat v prohlížeči počítače.

VEED Captions

Tato aplikace je nepostradatelná pro tvorbu automatických titulků u krátkých videí. Titulky jsou dnes nutnost, protože spousta uživatelů konzumuje videa bez zvuku.

Obrovskou přidanou hodnotou VEED Captions je to, že dokáže titulky generovat rychlostí blesku. I když automatické titulkování zvládne dnes i Canva, tato aplikace je zatím v titulkování jedničkou, a to díky ceně a příjemnému uživatelskému prostředí. Za celoroční předplatné ve stovkách korun si může uživatel nastavit svoje vlastní grafické pojetí titulků, ať už co se týká výběru fontu písma, jeho barvy, velikosti i systému, jak se mají titulky ve videu zobrazovat.

Češtinu zvládá na jedničku a dokáže pomocí umělé inteligence rozpoznat slova, která jsou ve videu špatně vyslovena. Chybná slova lze jednoduše opravit a export probíhá do rozlišení až 4K.

Příklad návrhu kampaně

A jak tedy začít se samotným návrhem kampaně? Zadal jsem aplikaci ChatGPT a Gemini níže uvedený úkol. Jak si se zadáním aplikace poradily?

Zadání znělo
Jsem pekař a mám malou pekárnu. Rád bych vytvořil vizuální kampaň pro sociální sítě, která by měla zdůraznit kvalitu a proces výroby chlebů. Navrhni mi, jak by taková kampaň měla vypadat.

Co navrhuje Gemini?

Návrh 1: Zaostřete na proces pečení

  • Snímky z procesu pečení: Zachyťte různé fáze pečení chleba, od míchání těsta po pečení v troubě. 
  • Ukažte, jak pečlivě a s láskou k řemeslu pečete své chleby.
  • Video s časovým odstupem: Vytvořte video, které ukazuje celý proces pečení od začátku do konce. Můžete použít rychlý záběr nebo časosběr, aby to bylo zajímavé. 
  • Použijte hudbu: Vyberte hudbu, která evokuje pocit tepla, pohody a domácí atmosféry.
  • Přidejte text: Použijte text, který popisuje proces pečení a zdůrazňuje kvalitu vašich surovin a pečení.

Návrh 2: Zaměřte se na texturu a vůni chleba

  • Snímky detailů chleba: Zachyťte texturu, barvu a vůni chleba. Ukažte, jak je čerstvý a lákavý.
  • Video s krájením chleba: Vytvořte video, které ukazuje, jak se chleba krásně krájí a jak má křupavou kůrku a měkkou dužinu.
  • Použijte zvuk: Zaznamenejte zvuk krájení chleba nebo jeho křupnutí.
  • Přidejte text: Použijte text, který popisuje chuť a vůni chleba.

Návrh 3: Kombinujte proces a produkt

  • Snímky procesu a produktu: Kombinujte snímky z procesu pečení s detailními snímky chleba. Ukažte, jak proces ovlivňuje kvalitu produktu.
  • Video s časovým odstupem a krájením: Vytvořte video, které kombinuje časosběr procesu pečení s krájením chleba.
  • Použijte hudbu a zvuk: Kombinujte hudbu se zvukem krájení chleba.
  • Přidejte text: Použijte text, který popisuje proces pečení a kvalitu chleba.

Co navrhuje ChatGPT

1. Úvodní myšlenka kampaně

Začni silným, zapamatovatelným sloganem, který vyjadřuje kvalitu a péči, kterou vkládáš do každého bochníku. Například:

  • „S láskou k tradičnímu řemeslu.“
  • „Každý chléb má svůj příběh.“
  • „Chleba, který je tvořen s péčí a vášní.“

2. Fáze přípravy

Vytvoř sérii vizuálů, které ukážou jednotlivé fáze výroby chleba. Můžeš použít i krátká videa nebo animace. Některé z fází, které by se mohly objevit:

  • Výběr surovin: Fotografie čerstvých surovin – kvalitní mouka, voda, kvasnice. Můžeš například ukázat detailní záběry na ruce, které vybírají nejlepší ingredience.
  • Příprava těsta: Fotografii nebo video, jak ručně zpracováváš těsto. Případně i záběr na mísení, hnětení, kvasení. Tento moment může být doprovázen textem o tom, jak důležitý je čas a trpělivost při tvorbě správného těsta.
  • Pečení: Záběr na pece, jak se chléb pomalu peče. Můžeš použít i zpomalené záběry, jak chléb roste, jak praská kůrka. Tento moment symbolizuje péči a pozornost věnovanou každému detailu.
  • Hotový produkt: Krásně naservírovaný chléb na stole, s jemným slunečním světlem pro vytvoření příjemné atmosféry. Tady by mohl být záběr na šťavnatý, čerstvě nakrájený chléb s křupavou kůrkou.

3. Zdůraznění kvality

Důležité je, aby kampaň vyjadřovala, že ve tvé pekárně se používají kvalitní, přírodní suroviny. Zde bys mohl přidat:

  • Certifikáty nebo označení kvality (pokud nějaké máš).
  • Příběh o původu ingrediencí: Například odkud pochází mouka nebo jiná ingredience.
  • Bez umělých přísad: Pokud je to pravda, můžeš to vyzdvihnout.

4. Propojení s komunitou

Lidé se dnes rádi spojují s místními výrobci a vidí příběhy, které se skrývají za výrobky. To můžeš ukázat takto:

  • Zákazníci a jejich zkušenosti: Sdílej příběhy spokojených zákazníků, kteří popisují, co pro ně znamená koupit čerstvý domácí chléb.
  • Fotky zákazníků: Pokud to je možné, nech je sdílet fotky na sociálních sítích (např. s jejich oblíbeným chlebem) a použij hashtagy.
  • Ukázka týmového ducha: Fotky tebe a tvých zaměstnanců při práci, abys ukázal, že za tvou pekárnou stojí tým lidí, který dává do všeho to nejlepší.

5. Vizuální styl a tón kampaně

Vizuální styl kampaně by měl být autentický a teplý. Použij přírodní tóny, jako jsou hnědá, zlatá, krémová a bílá, které evokují pocit čerstvosti a kvality.

  • Použití textur: Záběry na textury chleba (křupavá kůrka, měkký střed), mouku, ruku při hnětení, vše vypadá velmi autenticky a osobně.
  • Světlo: Přirozené světlo je klíčové. Světlo zdůrazní čerstvost a kvalitu.
  • Filtr: Možná jemný vintage filtr pro to, aby vše vypadalo jako „tradiční řemeslo“.

6. Pravidelnost a zapojení

  • Pravidelné příspěvky: Udělej si plán pro pravidelné příspěvky na sociálních sítích. Např. každý týden ukazovat jinou fázi procesu nebo nový produkt, který pečeš.
  • Příběhy: Instagram Stories nebo Facebook Stories jsou skvélé pro ukázání „běžného dne v pekárně“, zašpičkování příběhů od zákazníků a rychlé ukázky přípravy.

7. Interakce s fanoušky

  • Výzvy pro sledující: Požádej své sledující, aby sdíleli fotky, jak si užívají tvůj chléb. Například soutěže, kde lidé mohou vyhrát speciální chléb nebo slevu.
  • Hlasování o nových chutích: Můžeš se jich ptát na jejich oblíbené kombinace surovin nebo nové chlebové recepty, které by chtěli vyzkoušet.

8. Hashtagy

Použij relevantní a chytlavé hashtagy, které mohou zlepšit dosah kampaně. Například:

Marketing meeting Influenceři a sociální sítě

#ChlébSrdcem
#TradičníPekárna
#ZdravýChléb
#Pečenosúsměvem

9. Spolupráce s influencery (volitelné)

Pokud máš nějaké lokální food blogery nebo influencery, můžeš je pozvat do pekárny na ochutnávku a nechat je sdílet zážitky se svými sledujícími.

Zajímá vás toto téma? Chcete se o něm dozvědět víc?

Objednejte si upozornění na nově vydané články do vašeho mailu. Žádný článek vám tak neuteče.


Autor článku

Michael Hovorka je šéfredaktorem Podnikatel.cz. Zaměřuje se na digitální tvůrce, monetizaci obsahu, osobní značku, marketing a digitální trendy. Profil autora →

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