mirror of
https://github.com/bytedance/xgplayer.git
synced 2025-04-05 11:18:46 +08:00
feat: (xgplayer-ads)支持设置广告自动播放和动态更新广告
This commit is contained in:
parent
cfb82367df
commit
34bfc82677
@ -161,10 +161,24 @@
|
||||
TagURL 请求后转为 AdsResponse <input type="checkbox" /> <br />
|
||||
AdsResponse: <textarea style="width: 500px"></textarea>
|
||||
</label>
|
||||
|
||||
<label id="autoplay" class="hidden mr-3 mb-2 p-1 bg-gray-200"
|
||||
>自动播放<input type="checkbox"
|
||||
/></label>
|
||||
<label id="autoplay" class="mr-3 mb-2 p-1 bg-gray-200">
|
||||
autoplay<input type="checkbox" checked="true"/>
|
||||
</label>
|
||||
<label id="autoplay-ad" class="mr-3 mb-2 p-1 bg-gray-200">
|
||||
adWillAutoPlay<input type="checkbox" checked="true"/>
|
||||
<button id="play-ad-opt" style="visibility: hidden" class="py-1 px-2 bg-green-500 text-white shadow-md mr-2">
|
||||
Play
|
||||
</button>
|
||||
</label>
|
||||
<label id="autoplay-ad-breaks" class="mr-3 mb-2 p-1 bg-gray-200">
|
||||
autoPlayAdBreaks<input type="checkbox" checked="true"/>
|
||||
<button id="play-ad-break-opt" style="visibility: hidden" class="py-1 px-2 bg-green-500 text-white shadow-md mr-2">
|
||||
Play
|
||||
</button>
|
||||
</label>
|
||||
<label id="reset-player" class="mr-3 mb-2 p-1 bg-gray-200">
|
||||
重置播放器<input type="checkbox" checked="true"/>
|
||||
</label>
|
||||
</div>
|
||||
<div class="flex flex-wrap">
|
||||
<button id="reset-opt" class="py-1 px-2 bg-green-500 text-white shadow-md mr-2">
|
||||
|
@ -7,6 +7,12 @@ const dbApplyOpt = document.getElementById('apply-opt')
|
||||
const doPresetUrl = document.getElementById('ima-preset-url')
|
||||
const doAdsRequest = document.getElementById('ima-ads-request')
|
||||
const doAdsResponse = document.getElementById('ima-ads-response')
|
||||
const doAutoPlay = document.getElementById('autoplay')
|
||||
const doAutoPlayAd = document.getElementById('autoplay-ad')
|
||||
const doAutoPlayAdBreaks = document.getElementById('autoplay-ad-breaks')
|
||||
const doPlayAdOpt = document.getElementById('play-ad-opt')
|
||||
const doPlayAdBreakOpt = document.getElementById('play-ad-break-opt')
|
||||
const doResetPlayerOpt = document.getElementById('reset-player')
|
||||
|
||||
// TODO: delete
|
||||
Logger.enable()
|
||||
@ -53,20 +59,35 @@ function initSetting() {
|
||||
var opts = Object.assign({}, defaultOpt(), cachedOpt, {
|
||||
useAdsRequest: doAdsRequest.getElementsByTagName('input')[0].checked,
|
||||
useAdsResponse: doAdsResponse.getElementsByTagName('input')[0].checked,
|
||||
adTagUrl: doPresetUrl.getElementsByTagName('input')[0].value
|
||||
adTagUrl: doPresetUrl.getElementsByTagName('input')[0].value,
|
||||
autoplay: doAutoPlay.getElementsByTagName('input')[0].checked,
|
||||
adWillAutoPlay: doAutoPlayAd.getElementsByTagName('input')[0].checked,
|
||||
autoPlayAdBreaks: doAutoPlayAdBreaks.getElementsByTagName('input')[0].checked,
|
||||
resetPlayer: doResetPlayerOpt.getElementsByTagName('input')[0].checked,
|
||||
})
|
||||
|
||||
return opts
|
||||
}
|
||||
|
||||
function newPlayer () {
|
||||
if (!settings.resetPlayer && window.player) {
|
||||
window.player.plugins.ad.updateConfig({
|
||||
adsRequest: generateAdsRequest(settings),
|
||||
adsResponse: settings.adsResponse,
|
||||
adTagUrl: settings.adTagUrl,
|
||||
adWillAutoPlay: settings.adWillAutoPlay,
|
||||
autoPlayAdBreaks: settings.autoPlayAdBreaks,
|
||||
})
|
||||
window.player.plugins.ad.requestAds()
|
||||
return
|
||||
}
|
||||
if (window.player) {
|
||||
window.player.destroy()
|
||||
}
|
||||
window.player = new Player({
|
||||
id: 'video',
|
||||
url: '//lf3-static.bytednsdoc.com/obj/eden-cn/nupenuvpxnuvo/xgplayer_doc/xgplayer-demo-720p.mp4',
|
||||
autoplay: true,
|
||||
autoplay: settings.autoplay,
|
||||
width: '80%',
|
||||
height: 700,
|
||||
plugins: [AdPlugin],
|
||||
@ -75,7 +96,9 @@ function newPlayer () {
|
||||
ima: {
|
||||
adsRequest: generateAdsRequest(settings),
|
||||
adsResponse: settings.adsResponse,
|
||||
adTagUrl: settings.adTagUrl
|
||||
adTagUrl: settings.adTagUrl,
|
||||
adWillAutoPlay: settings.adWillAutoPlay,
|
||||
autoPlayAdBreaks: settings.autoPlayAdBreaks,
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -87,6 +110,22 @@ function newPlayer () {
|
||||
player.on(AdEvents.AD_PAUSE, function (e) {
|
||||
console.log('=====> AD_PAUSE', e)
|
||||
})
|
||||
|
||||
if (settings.adWillAutoPlay) {
|
||||
doPlayAdOpt.style.visibility = 'hidden'
|
||||
} else {
|
||||
player.once(AdEvents.IMA_AD_LOADED, function (e) {
|
||||
doPlayAdOpt.style.visibility = 'visible'
|
||||
})
|
||||
}
|
||||
|
||||
if (settings.autoPlayAdBreaks) {
|
||||
doPlayAdBreakOpt.style.visibility = 'hidden'
|
||||
} else {
|
||||
player.once(AdEvents.IMA_AD_BREAK_READY, function (e) {
|
||||
doPlayAdBreakOpt.style.visibility = 'visible'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function initPlayer() {
|
||||
@ -110,6 +149,14 @@ dbApplyOpt.addEventListener('click', function () {
|
||||
initPlayer()
|
||||
})
|
||||
|
||||
doPlayAdOpt.addEventListener('click', function () {
|
||||
window.player?.plugins.ad.playAds()
|
||||
})
|
||||
|
||||
doPlayAdBreakOpt.addEventListener('click', function () {
|
||||
window.player?.plugins.ad.playAds()
|
||||
})
|
||||
|
||||
doPresetUrl.getElementsByTagName('select')[0].onchange = function () {
|
||||
if (this.value) {
|
||||
const input = doPresetUrl.getElementsByTagName('input')[0]
|
||||
|
@ -29,6 +29,9 @@ export class BaseAdManager extends EventEmitter {
|
||||
* @type {V}
|
||||
*/
|
||||
this.options = options
|
||||
/**
|
||||
* @type {T}
|
||||
*/
|
||||
this.config = options.config || {}
|
||||
this.player = options.player
|
||||
this.mediaElement = options.player.media || options.player.video
|
||||
@ -51,6 +54,13 @@ export class BaseAdManager extends EventEmitter {
|
||||
this._isMediaEnded = false
|
||||
}
|
||||
|
||||
updateConfig (config = {}) {
|
||||
this.config = {
|
||||
...this.config,
|
||||
...config
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {boolean}
|
||||
*/
|
||||
|
@ -14,3 +14,6 @@ export const IMA_AD_TIME_UPDATE = 'ima_ad_time_update'
|
||||
export const IMA_AD_VOLUME_CHANGE = 'ima_ad_volume_change'
|
||||
export const IMA_AD_SEEKING = 'ima_ad_seeking'
|
||||
export const IMA_AD_SEEKED = 'ima_ad_seeked'
|
||||
export const IMA_AD_LOADED = 'ima_ad_loaded'
|
||||
export const IMA_AD_BREAK_READY = 'ima_ad_break_ready'
|
||||
export const IMA_READY_TO_PLAY = 'ima_ready_to_play'
|
||||
|
@ -11,6 +11,8 @@ const logger = new Logger('AdsPluginImaAdManager')
|
||||
* adTagUrl?: string,
|
||||
* adsResponse?: string,
|
||||
* adsRequest?: google.ima.AdsRequest,
|
||||
* adWillAutoPlay?: boolean,
|
||||
* autoPlayAdBreaks?: boolean,
|
||||
* }} ImaConfig
|
||||
*/
|
||||
|
||||
@ -46,10 +48,11 @@ export class ImaAdManager extends BaseAdManager {
|
||||
}
|
||||
|
||||
init () {
|
||||
this._initConfig()
|
||||
this._initMediaEvents()
|
||||
this._initContainer()
|
||||
this._initLoader()
|
||||
this._loadAdsRequest()
|
||||
this._initAdsRequest()
|
||||
}
|
||||
|
||||
destroy () {
|
||||
@ -59,14 +62,24 @@ export class ImaAdManager extends BaseAdManager {
|
||||
this._destroyLoader()
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_initConfig () {
|
||||
this.adWillAutoPlay = this.config.adWillAutoPlay !== false ? true : false
|
||||
this.autoPlayAdBreaks = this.config.autoPlayAdBreaks !== false ? true : false
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_initMediaEvents () {
|
||||
const { player } = this
|
||||
|
||||
player.on(Events.VIDEO_RESIZE, this.onMediaResize)
|
||||
player.on(Events.ENDED, this.onMediaEnded)
|
||||
player.on(Events.VIDEO_RESIZE, this._onMediaResize)
|
||||
player.on(Events.ENDED, this._onMediaEnded)
|
||||
player.on(Events.PLAY, this._onMediaPlay)
|
||||
player.on(Events.PAUSED, this._onMediaPause)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -75,8 +88,10 @@ export class ImaAdManager extends BaseAdManager {
|
||||
_removeMediaEvents () {
|
||||
const { player } = this
|
||||
|
||||
player.off(Events.VIDEO_RESIZE, this.onMediaResize)
|
||||
player.off(Events.ENDED, this.onMediaEnded)
|
||||
player.off(Events.VIDEO_RESIZE, this._onMediaResize)
|
||||
player.off(Events.ENDED, this._onMediaEnded)
|
||||
player.off(Events.PLAY, this._onMediaPlay)
|
||||
player.off(Events.PAUSED, this._onMediaPause)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -99,6 +114,8 @@ export class ImaAdManager extends BaseAdManager {
|
||||
// Create ads loader.
|
||||
const adsLoader = (this.adsLoader = new google.ima.AdsLoader(this.displayContainer))
|
||||
|
||||
adsLoader.getSettings().setAutoPlayAdBreaks(this.autoPlayAdBreaks)
|
||||
|
||||
// Listen and respond to ads loaded and error events.
|
||||
adsLoader.addEventListener(
|
||||
google.ima.AdsManagerLoadedEvent.Type.ADS_MANAGER_LOADED,
|
||||
@ -138,28 +155,14 @@ export class ImaAdManager extends BaseAdManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the ads request.
|
||||
* @private
|
||||
*/
|
||||
_loadAdsRequest () {
|
||||
_initAdsRequest () {
|
||||
const { adsRequest, adsResponse, adTagUrl } = this.config
|
||||
|
||||
if (adsRequest) {
|
||||
this.requestAds(adsRequest)
|
||||
} else if (adsResponse || adTagUrl) {
|
||||
// Request video ads.
|
||||
const adsRequest = new google.ima.AdsRequest()
|
||||
|
||||
if (adsResponse) {
|
||||
adsRequest.adsResponse = adsResponse
|
||||
}
|
||||
if (adTagUrl) {
|
||||
adsRequest.adTagUrl = adTagUrl
|
||||
}
|
||||
|
||||
this.requestAds(adsRequest)
|
||||
if (adsRequest || adsResponse || adTagUrl) {
|
||||
this.requestAds()
|
||||
} else {
|
||||
logger.warn('adsRequest should be provided')
|
||||
this.emit(ADEvents.IMA_READY_TO_PLAY)
|
||||
}
|
||||
}
|
||||
|
||||
@ -167,7 +170,7 @@ export class ImaAdManager extends BaseAdManager {
|
||||
* End event listener to tell the SDK can play any post-roll ads.
|
||||
* @private
|
||||
*/
|
||||
onMediaEnded = () => {
|
||||
_onMediaEnded = () => {
|
||||
// An ad might have been playing in the content element, in which case the
|
||||
// content has not actually ended.
|
||||
if (this._isAdRunning) return
|
||||
@ -179,7 +182,7 @@ export class ImaAdManager extends BaseAdManager {
|
||||
* End event listener to tell the SDK can play any post-roll ads.
|
||||
* @private
|
||||
*/
|
||||
onMediaResize = () => {
|
||||
_onMediaResize = () => {
|
||||
const { player } = this
|
||||
const viewMode = this.isFullScreen()
|
||||
? google.ima.ViewMode.FULLSCREEN
|
||||
@ -187,14 +190,26 @@ export class ImaAdManager extends BaseAdManager {
|
||||
this.adsManager?.resize(player.sizeInfo.width, player.sizeInfo.height, viewMode)
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_onMediaPlay = () => {
|
||||
this._mediaPlayed = true
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_onMediaPause = () => {
|
||||
this._mediaPlayed = false
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the ad manager loading and sets ad event listeners.
|
||||
* @param {!google.ima.AdsManagerLoadedEvent} ev
|
||||
* @private
|
||||
*/
|
||||
onAdsManagerLoaded = ev => {
|
||||
const { player } = this
|
||||
|
||||
// Get the ads manager.
|
||||
const adsRenderingSettings = new google.ima.AdsRenderingSettings()
|
||||
adsRenderingSettings.restoreCustomPlaybackStateOnAdBreakComplete = true
|
||||
@ -211,41 +226,49 @@ export class ImaAdManager extends BaseAdManager {
|
||||
}
|
||||
|
||||
this._initAdsManagerEventListeners()
|
||||
this._initAdsManager()
|
||||
|
||||
try {
|
||||
if (this.mediaPlayed) {
|
||||
this.playAds()
|
||||
} else {
|
||||
player.once(Events.PLAY, () => {
|
||||
this.mediaPlayed = true
|
||||
this.playAds()
|
||||
})
|
||||
}
|
||||
} catch (adError) {
|
||||
this.onAdEvent()
|
||||
if ((this.adWillAutoPlay && !cuePoints.length) || (this.autoPlayAdBreaks && cuePoints.length)) {
|
||||
this._doOnPlay(() => {
|
||||
this._actualPlayAds()
|
||||
})
|
||||
}
|
||||
|
||||
this.emit(ADEvents.IMA_READY_TO_PLAY)
|
||||
this.emit(ADEvents.IMA_AD_MANAGER_READY, { adsManager })
|
||||
}
|
||||
|
||||
playAds () {
|
||||
if (!this.displayContainerInitialized) {
|
||||
// Initialize the container. Must be done through a user action on mobile
|
||||
// devices.
|
||||
this.displayContainer.initialize()
|
||||
this.displayContainerInitialized = true
|
||||
if (!this.autoPlayAdBreaks || !this.adWillAutoPlay) {
|
||||
this._doOnPlay(() => {
|
||||
this._actualPlayAds()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const { player } = this
|
||||
const viewMode = this.isFullScreen()
|
||||
? google.ima.ViewMode.FULLSCREEN
|
||||
: google.ima.ViewMode.NORMAL
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_actualPlayAds () {
|
||||
try {
|
||||
|
||||
// Initialize the ads manager. Ad rules playlist will start at this time.
|
||||
this.adsManager.init(player.sizeInfo.width, player.sizeInfo.height, viewMode)
|
||||
// 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.
|
||||
this.adsManager.start()
|
||||
this.adsManager.start()
|
||||
} catch (adError) {
|
||||
this.onAdError(adError)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_doOnPlay (callback) {
|
||||
if (this._mediaPlayed) {
|
||||
callback()
|
||||
} else {
|
||||
this.player.once(Events.PLAY, () => {
|
||||
callback()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -289,6 +312,30 @@ export class ImaAdManager extends BaseAdManager {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the ads manager.
|
||||
*/
|
||||
_initAdsManager () {
|
||||
try {
|
||||
if (!this.displayContainerInitialized) {
|
||||
// Initialize the container. Must be done through a user action on mobile
|
||||
// devices.
|
||||
this.displayContainer.initialize()
|
||||
this.displayContainerInitialized = true
|
||||
}
|
||||
|
||||
const { player } = this
|
||||
const viewMode = this.isFullScreen()
|
||||
? google.ima.ViewMode.FULLSCREEN
|
||||
: google.ima.ViewMode.NORMAL
|
||||
|
||||
// Initialize the ads manager. Ad rules playlist will start at this time.
|
||||
this.adsManager.init(player.sizeInfo.width, player.sizeInfo.height, viewMode)
|
||||
} catch (adError) {
|
||||
this.onAdError(adError)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles ad errors.
|
||||
* @param {!google.ima.AdErrorEvent} ev
|
||||
@ -315,12 +362,21 @@ export class ImaAdManager extends BaseAdManager {
|
||||
logger.log('AdEvent', ev?.type, ev?.getAd())
|
||||
|
||||
switch (ev?.type) {
|
||||
case google.ima.AdEvent.Type.AD_BREAK_READY: {
|
||||
this.player.emit(ADEvents.IMA_AD_BREAK_READY, {
|
||||
ad
|
||||
})
|
||||
break
|
||||
}
|
||||
// Fires when ad data is available.
|
||||
// This is the first event sent for an ad.
|
||||
case google.ima.AdEvent.Type.LOADED: {
|
||||
if (!ad.isLinear()) {
|
||||
this.mediaElement?.play()
|
||||
}
|
||||
this.player.emit(ADEvents.IMA_AD_LOADED, {
|
||||
ad
|
||||
})
|
||||
break
|
||||
}
|
||||
// Fires when media content should be resumed.
|
||||
@ -386,16 +442,43 @@ export class ImaAdManager extends BaseAdManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!google.ima.AdsRequest} payload
|
||||
* https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/reference/js/google.ima.AdsRequest
|
||||
* @private
|
||||
*/
|
||||
requestAds (payload) {
|
||||
_reset () {
|
||||
this._isAdRunning = false
|
||||
this.adsManager?.destroy()
|
||||
|
||||
logger.log('requestAds', JSON.stringify(payload))
|
||||
|
||||
this.adsManager = null
|
||||
this.adsLoader?.contentComplete()
|
||||
this.adsLoader?.requestAds(payload)
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the AdsRequest and request ads through the AdsLoader.
|
||||
*/
|
||||
requestAds () {
|
||||
const { adsRequest: providedAdsRequest, adsResponse, adTagUrl } = this.config
|
||||
const { player } = this
|
||||
|
||||
const adsRequest = new google.ima.AdsRequest()
|
||||
|
||||
adsRequest.linearAdSlotWidth = player.sizeInfo.width
|
||||
adsRequest.linearAdSlotHeight = player.sizeInfo.height
|
||||
adsRequest.nonLinearAdSlotWidth = player.sizeInfo.width
|
||||
adsRequest.nonLinearAdSlotHeight = player.sizeInfo.height
|
||||
adsRequest.setAdWillAutoPlay(this.adWillAutoPlay)
|
||||
|
||||
if (adTagUrl) {
|
||||
adsRequest.adTagUrl = adTagUrl
|
||||
} else if (adsResponse) {
|
||||
adsRequest.adsResponse = adsResponse
|
||||
} else if (providedAdsRequest && typeof providedAdsRequest === 'object') {
|
||||
Object.keys(providedAdsRequest).forEach((key) => {
|
||||
adsRequest[key] = providedAdsRequest[key]
|
||||
})
|
||||
}
|
||||
|
||||
logger.log('requestAds', JSON.stringify(adsRequest))
|
||||
|
||||
this.adsLoader?.requestAds(adsRequest)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -422,4 +505,10 @@ export class ImaAdManager extends BaseAdManager {
|
||||
skip () {
|
||||
return this.adsManager?.skip()
|
||||
}
|
||||
|
||||
updateConfig (config) {
|
||||
super.updateConfig(config)
|
||||
this._initConfig()
|
||||
this._reset()
|
||||
}
|
||||
}
|
||||
|
@ -110,22 +110,26 @@ export class AdsPlugin extends Plugin {
|
||||
displayContainer: this.root
|
||||
})
|
||||
|
||||
this.csManager.on(AdEvents.IMA_AD_LOADER_READY, () => {
|
||||
this.emit(AdEvents.IMA_AD_LOADER_READY)
|
||||
})
|
||||
this.csManager.on(AdEvents.IMA_AD_MANAGER_READY, () => {
|
||||
this.csManager.once(AdEvents.IMA_READY_TO_PLAY, () => {
|
||||
this.initPromise?.resolve()
|
||||
this.emit(AdEvents.IMA_AD_MANAGER_READY)
|
||||
})
|
||||
|
||||
this.csManager.init()
|
||||
}
|
||||
|
||||
requestAds (payload) {
|
||||
this.csManager?.requestAds(payload)
|
||||
requestAds () {
|
||||
this.csManager?.requestAds()
|
||||
}
|
||||
|
||||
playAds () {
|
||||
this.csManager?.playAds()
|
||||
}
|
||||
|
||||
destroy () {
|
||||
this.csManager?.destroy()
|
||||
}
|
||||
|
||||
updateConfig (config) {
|
||||
this.csManager?.updateConfig(config)
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user