prebid.js 7.22.0 → 7.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/33acrossBidAdapter.js +1 -1
- package/dist/aaxBlockmeterRtdProvider.js +1 -0
- package/dist/adagioBidAdapter.js +1 -1
- package/dist/adbookpspBidAdapter.js +1 -1
- package/dist/adgenerationBidAdapter.js +1 -1
- package/dist/admaticBidAdapter.js +1 -0
- package/dist/adrelevantisBidAdapter.js +1 -1
- package/dist/adtrgtmeBidAdapter.js +1 -1
- package/dist/adxcgBidAdapter.js +1 -1
- package/dist/adyoulikeBidAdapter.js +1 -1
- package/dist/ajaBidAdapter.js +1 -1
- package/dist/amxBidAdapter.js +1 -1
- package/dist/amxIdSystem.js +1 -1
- package/dist/analyticsAdapter.js +1 -1
- package/dist/appierAnalyticsAdapter.js +1 -1
- package/dist/appnexusBidAdapter.js +1 -1
- package/dist/asoBidAdapter.js +1 -1
- package/dist/audiencerunBidAdapter.js +1 -1
- package/dist/axonixBidAdapter.js +1 -1
- package/dist/bidViewability.js +1 -1
- package/dist/bidViewabilityIO.js +1 -1
- package/dist/bidglassBidAdapter.js +1 -1
- package/dist/big-richmediaBidAdapter.js +1 -1
- package/dist/bluebillywigBidAdapter.js +1 -1
- package/dist/bridgewellBidAdapter.js +1 -1
- package/dist/brightMountainMediaBidAdapter.js +1 -1
- package/dist/browsiRtdProvider.js +1 -1
- package/dist/carodaBidAdapter.js +1 -1
- package/dist/chtnwBidAdapter.js +1 -0
- package/dist/cleanioRtdProvider.js +1 -1
- package/dist/concertBidAdapter.js +1 -1
- package/dist/connectIdSystem.js +1 -1
- package/dist/connectadBidAdapter.js +1 -1
- package/dist/consentManagement.js +1 -1
- package/dist/consentManagementUsp.js +1 -1
- package/dist/consumableBidAdapter.js +1 -1
- package/dist/conversantBidAdapter.js +1 -1
- package/dist/craftBidAdapter.js +1 -1
- package/dist/criteoBidAdapter.js +1 -1
- package/dist/currency.js +1 -1
- package/dist/dependencies.json +19 -0
- package/dist/dfpAdServerVideo.js +1 -1
- package/dist/dgkeywordRtdProvider.js +1 -1
- package/dist/dspxBidAdapter.js +1 -1
- package/dist/eplanningBidAdapter.js +1 -1
- package/dist/finativeBidAdapter.js +1 -1
- package/dist/gdprEnforcement.js +1 -1
- package/dist/glimpseBidAdapter.js +1 -1
- package/dist/gmosspBidAdapter.js +1 -1
- package/dist/goldbachBidAdapter.js +1 -1
- package/dist/googleAnalyticsAdapter.js +1 -1
- package/dist/gridBidAdapter.js +1 -1
- package/dist/gridNMBidAdapter.js +1 -1
- package/dist/growthCodeIdSystem.js +1 -1
- package/dist/gumgumBidAdapter.js +1 -1
- package/dist/h12mediaBidAdapter.js +1 -1
- package/dist/id5AnalyticsAdapter.js +1 -1
- package/dist/id5IdSystem.js +1 -1
- package/dist/impactifyBidAdapter.js +1 -1
- package/dist/improvedigitalBidAdapter.js +1 -1
- package/dist/inmarBidAdapter.js +1 -1
- package/dist/insticatorBidAdapter.js +1 -1
- package/dist/instreamTracking.js +1 -1
- package/dist/ixBidAdapter.js +1 -1
- package/dist/jixieBidAdapter.js +1 -1
- package/dist/justpremiumBidAdapter.js +1 -1
- package/dist/jwplayerVideoProvider.js +1 -0
- package/dist/kargoBidAdapter.js +1 -1
- package/dist/konduitAnalyticsAdapter.js +1 -1
- package/dist/kueezBidAdapter.js +1 -1
- package/dist/kueezRtbBidAdapter.js +1 -0
- package/dist/lassoBidAdapter.js +1 -1
- package/dist/lifestreetBidAdapter.js +1 -1
- package/dist/liveyieldAnalyticsAdapter.js +1 -1
- package/dist/logicadBidAdapter.js +1 -1
- package/dist/loglyliftBidAdapter.js +1 -1
- package/dist/magniteAnalyticsAdapter.js +1 -1
- package/dist/malltvAnalyticsAdapter.js +1 -1
- package/dist/marsmediaBidAdapter.js +1 -1
- package/dist/mediafuseBidAdapter.js +1 -1
- package/dist/mediakeysBidAdapter.js +1 -1
- package/dist/mediasquareBidAdapter.js +1 -1
- package/dist/mgidBidAdapter.js +1 -1
- package/dist/mgidRtdProvider.js +1 -0
- package/dist/minutemediaBidAdapter.js +1 -1
- package/dist/multibid.js +1 -1
- package/dist/not-for-prod/prebid.js +153 -141
- package/dist/oguryBidAdapter.js +1 -1
- package/dist/onetagBidAdapter.js +1 -1
- package/dist/ooloAnalyticsAdapter.js +1 -1
- package/dist/openxOrtbBidAdapter.js +1 -1
- package/dist/ortbConverter.js +1 -0
- package/dist/outbrainBidAdapter.js +1 -1
- package/dist/oxxionRtdProvider.js +1 -0
- package/dist/parrableIdSystem.js +1 -1
- package/dist/pbsExtensions.js +1 -0
- package/dist/permutiveRtdProvider.js +1 -1
- package/dist/pixfutureBidAdapter.js +1 -1
- package/dist/prebid-core.js +1 -1
- package/dist/prebidServerBidAdapter.js +1 -1
- package/dist/priceFloors.js +1 -1
- package/dist/pubCommonId.js +1 -1
- package/dist/publinkIdSystem.js +1 -1
- package/dist/pubmaticBidAdapter.js +1 -1
- package/dist/pubwiseAnalyticsAdapter.js +1 -1
- package/dist/pxyzBidAdapter.js +1 -1
- package/dist/quantcastBidAdapter.js +1 -1
- package/dist/readpeakBidAdapter.js +1 -1
- package/dist/relaidoBidAdapter.js +1 -1
- package/dist/rhythmoneBidAdapter.js +1 -1
- package/dist/riseBidAdapter.js +1 -1
- package/dist/rtdModule.js +1 -1
- package/dist/rubiconAnalyticsAdapter.js +1 -1
- package/dist/rubiconBidAdapter.js +1 -1
- package/dist/schain.js +1 -1
- package/dist/seedingAllianceBidAdapter.js +1 -1
- package/dist/seedtagBidAdapter.js +1 -1
- package/dist/sharethroughAnalyticsAdapter.js +1 -1
- package/dist/sharethroughBidAdapter.js +1 -1
- package/dist/shinezBidAdapter.js +1 -1
- package/dist/smaatoBidAdapter.js +1 -1
- package/dist/smartadserverBidAdapter.js +1 -1
- package/dist/smartxBidAdapter.js +1 -1
- package/dist/smilewantedBidAdapter.js +1 -1
- package/dist/sonobiBidAdapter.js +1 -1
- package/dist/sovrnAnalyticsAdapter.js +1 -1
- package/dist/sovrnBidAdapter.js +1 -1
- package/dist/spotxBidAdapter.js +1 -1
- package/dist/sspBCBidAdapter.js +1 -1
- package/dist/sublimeBidAdapter.js +1 -1
- package/dist/synacormediaBidAdapter.js +1 -1
- package/dist/targetVideoBidAdapter.js +1 -1
- package/dist/teadsBidAdapter.js +1 -1
- package/dist/teadsIdSystem.js +1 -1
- package/dist/trionBidAdapter.js +1 -1
- package/dist/tripleliftBidAdapter.js +1 -1
- package/dist/ttdBidAdapter.js +1 -1
- package/dist/ucfunnelAnalyticsAdapter.js +1 -1
- package/dist/underdogmediaBidAdapter.js +1 -1
- package/dist/undertoneBidAdapter.js +1 -1
- package/dist/userId.js +1 -1
- package/dist/vidazooBidAdapter.js +1 -1
- package/dist/video.js +1 -0
- package/dist/videoModule.js +1 -0
- package/dist/videobyteBidAdapter.js +1 -1
- package/dist/videojsVideoProvider.js +1 -0
- package/dist/visxBidAdapter.js +1 -1
- package/dist/vuukleBidAdapter.js +1 -1
- package/dist/widespaceBidAdapter.js +1 -1
- package/dist/winrBidAdapter.js +1 -1
- package/dist/yahoosspBidAdapter.js +1 -1
- package/dist/yieldmoBidAdapter.js +1 -1
- package/dist/yieldoneAnalyticsAdapter.js +1 -1
- package/integrationExamples/gpt/mgidRtdProvider_example.html +143 -0
- package/integrationExamples/videoModule/jwplayer/bidMarkedAsUsed.html +98 -0
- package/integrationExamples/videoModule/jwplayer/bidRequestScheduling.html +89 -0
- package/integrationExamples/videoModule/jwplayer/eventListeners.html +244 -0
- package/integrationExamples/videoModule/jwplayer/gamAdServerMediation.html +122 -0
- package/integrationExamples/videoModule/jwplayer/mediaMetadata.html +80 -0
- package/integrationExamples/videoModule/jwplayer/playlist.html +122 -0
- package/integrationExamples/videoModule/videojs/bidMarkedAsUsed.html +126 -0
- package/integrationExamples/videoModule/videojs/bidRequestScheduling.html +132 -0
- package/integrationExamples/videoModule/videojs/eventListeners.html +238 -0
- package/integrationExamples/videoModule/videojs/gamAdServerMediation.html +138 -0
- package/integrationExamples/videoModule/videojs/mediaMetadata.html +103 -0
- package/integrationExamples/videoModule/videojs/playlist.html +151 -0
- package/libraries/ortbConverter/README.md +378 -0
- package/libraries/ortbConverter/converter.js +135 -0
- package/libraries/ortbConverter/lib/composer.js +43 -0
- package/libraries/ortbConverter/lib/mergeProcessors.js +9 -0
- package/libraries/ortbConverter/lib/sizes.js +14 -0
- package/libraries/ortbConverter/processors/banner.js +40 -0
- package/libraries/ortbConverter/processors/default.js +167 -0
- package/libraries/ortbConverter/processors/mediaType.js +21 -0
- package/libraries/ortbConverter/processors/native.js +37 -0
- package/libraries/ortbConverter/processors/video.js +66 -0
- package/libraries/pbsExtensions/pbsExtensions.js +12 -0
- package/libraries/pbsExtensions/processors/aliases.js +17 -0
- package/libraries/pbsExtensions/processors/mediaType.js +23 -0
- package/libraries/pbsExtensions/processors/params.js +22 -0
- package/libraries/pbsExtensions/processors/pbs.js +99 -0
- package/libraries/pbsExtensions/processors/requestExtPrebid.js +30 -0
- package/libraries/pbsExtensions/processors/video.js +23 -0
- package/libraries/video/constants/enums.js +5 -0
- package/libraries/video/constants/events.js +97 -0
- package/libraries/video/constants/ortb.js +169 -0
- package/libraries/video/constants/vendorCodes.js +6 -0
- package/libraries/video/shared/eventHandler.js +18 -0
- package/libraries/video/shared/parentModule.js +82 -0
- package/libraries/video/shared/state.js +47 -0
- package/libraries/video/shared/vastXmlBuilder.js +77 -0
- package/libraries/video/shared/vastXmlEditor.js +115 -0
- package/modules/.submodules.json +7 -1
- package/modules/aaxBlockmeterRtdProvider.js +59 -0
- package/modules/aaxBlockmeterRtdProvider.md +48 -0
- package/modules/admaticBidAdapter.js +147 -0
- package/modules/admaticBidAdapter.md +48 -0
- package/modules/amxBidAdapter.js +1 -0
- package/modules/appnexusBidAdapter.js +38 -1
- package/modules/chtnwBidAdapter.js +110 -0
- package/modules/chtnwBidAdapter.md +31 -0
- package/modules/concertBidAdapter.js +44 -2
- package/modules/connectIdSystem.js +36 -23
- package/modules/connectIdSystem.md +3 -2
- package/modules/consentManagement.js +22 -1
- package/modules/consentManagementUsp.js +29 -7
- package/modules/criteoBidAdapter.js +25 -5
- package/modules/currency.js +9 -0
- package/modules/dgkeywordRtdProvider.js +3 -3
- package/modules/gridNMBidAdapter.js +10 -14
- package/modules/growthCodeIdSystem.js +9 -5
- package/modules/gumgumBidAdapter.js +4 -0
- package/modules/improvedigitalBidAdapter.js +191 -470
- package/modules/ixBidAdapter.js +54 -71
- package/modules/jwplayerVideoProvider.js +929 -0
- package/modules/jwplayerVideoProvider.md +25 -0
- package/modules/kargoBidAdapter.js +1 -1
- package/modules/kueezRtbBidAdapter.js +278 -0
- package/modules/kueezRtbBidAdapter.md +35 -0
- package/modules/magniteAnalyticsAdapter.js +6 -1
- package/modules/mgidRtdProvider.js +190 -0
- package/modules/mgidRtdProvider.md +51 -0
- package/modules/multibid/index.js +12 -0
- package/modules/openxOrtbBidAdapter.js +120 -275
- package/modules/oxxionRtdProvider.js +119 -0
- package/modules/oxxionRtdProvider.md +48 -0
- package/modules/permutiveRtdProvider.js +2 -1
- package/modules/permutiveRtdProvider.md +36 -1
- package/modules/prebidServerBidAdapter/index.js +19 -716
- package/modules/prebidServerBidAdapter/ortbConverter.js +274 -0
- package/modules/priceFloors.js +73 -1
- package/modules/pubmaticBidAdapter.js +21 -29
- package/modules/rtdModule/index.js +22 -1
- package/modules/schain.js +24 -1
- package/modules/spotxBidAdapter.js +16 -15
- package/modules/synacormediaBidAdapter.js +1 -1
- package/modules/teadsIdSystem.js +5 -0
- package/modules/tripleliftBidAdapter.js +1 -1
- package/modules/userId/eids.js +3 -10
- package/modules/userId/index.js +64 -6
- package/modules/videoModule/addingSubmodule.md +521 -0
- package/modules/videoModule/coreVideo.js +234 -0
- package/modules/videoModule/gamAdServerSubmodule.js +27 -0
- package/modules/videoModule/index.js +244 -0
- package/modules/videoModule/videoImpressionVerifier.js +206 -0
- package/modules/videojsVideoProvider.js +854 -0
- package/modules/videojsVideoProvider.md +17 -0
- package/package.json +12 -8
- package/src/adRendering.js +1 -1
- package/src/adapterManager.js +56 -7
- package/src/adloader.js +3 -1
- package/src/auction.js +6 -1
- package/src/events.js +5 -1
- package/src/pbjsORTB.js +35 -0
- package/src/prebid.js +137 -112
- package/src/targeting.js +10 -2
- package/src/utils/currency.js +16 -0
- package/src/utils.js +21 -0
- package/test/spec/auctionmanager_spec.js +15 -0
- package/test/spec/modules/aaxBlockmeter_spec.js +58 -0
- package/test/spec/modules/admaticBidAdapter_spec.js +46 -0
- package/test/spec/modules/chtnwBidAdapter_spec.js +105 -0
- package/test/spec/modules/concertBidAdapter_spec.js +56 -0
- package/test/spec/modules/connectIdSystem_spec.js +175 -5
- package/test/spec/modules/consentManagementUsp_spec.js +64 -18
- package/test/spec/modules/criteoBidAdapter_spec.js +28 -0
- package/test/spec/modules/dgkeywordRtdProvider_spec.js +3 -3
- package/test/spec/modules/eids_spec.js +10 -7
- package/test/spec/modules/ftrackIdSystem_spec.js +34 -22
- package/test/spec/modules/gumgumBidAdapter_spec.js +15 -0
- package/test/spec/modules/improvedigitalBidAdapter_spec.js +231 -211
- package/test/spec/modules/ixBidAdapter_spec.js +412 -350
- package/test/spec/modules/kueezRtbBidAdapter_spec.js +396 -0
- package/test/spec/modules/magniteAnalyticsAdapter_spec.js +26 -0
- package/test/spec/modules/mgidRtdProvider_spec.js +366 -0
- package/test/spec/modules/openxOrtbBidAdapter_spec.js +77 -49
- package/test/spec/modules/oxxionRtdProvider_spec.js +142 -0
- package/test/spec/modules/permutiveRtdProvider_spec.js +64 -5
- package/test/spec/modules/prebidServerBidAdapter_spec.js +139 -137
- package/test/spec/modules/realTimeDataModule_spec.js +65 -0
- package/test/spec/modules/tripleliftBidAdapter_spec.js +14 -0
- package/test/spec/modules/userId_spec.js +67 -1
- package/test/spec/modules/videoModule/coreVideo_spec.js +98 -0
- package/test/spec/modules/videoModule/pbVideo_spec.js +362 -0
- package/test/spec/modules/videoModule/shared/parentModule_spec.js +73 -0
- package/test/spec/modules/videoModule/shared/state_spec.js +26 -0
- package/test/spec/modules/videoModule/shared/vastXmlBuilder_spec.js +103 -0
- package/test/spec/modules/videoModule/shared/vastXmlEditor_spec.js +209 -0
- package/test/spec/modules/videoModule/submodules/jwplayerVideoProvider_spec.js +846 -0
- package/test/spec/modules/videoModule/submodules/videojsVideoProvider_spec.js +391 -0
- package/test/spec/modules/videoModule/videoImpressionVerifier_spec.js +112 -0
- package/test/spec/ortbConverter/banner_spec.js +203 -0
- package/test/spec/ortbConverter/composer_spec.js +69 -0
- package/test/spec/ortbConverter/converter_spec.js +283 -0
- package/test/spec/ortbConverter/currency_spec.js +40 -0
- package/test/spec/ortbConverter/default_processors_spec.js +61 -0
- package/test/spec/ortbConverter/gdpr_spec.js +38 -0
- package/test/spec/ortbConverter/mediaTypes_spec.js +67 -0
- package/test/spec/ortbConverter/mergeProcessors_spec.js +59 -0
- package/test/spec/ortbConverter/multibid_spec.js +35 -0
- package/test/spec/ortbConverter/native_spec.js +95 -0
- package/test/spec/ortbConverter/pbjsORTB_spec.js +67 -0
- package/test/spec/ortbConverter/pbsExtensions/aliases_spec.js +57 -0
- package/test/spec/ortbConverter/pbsExtensions/params_spec.js +96 -0
- package/test/spec/ortbConverter/pbsExtensions/video_spec.js +52 -0
- package/test/spec/ortbConverter/priceFloors_spec.js +143 -0
- package/test/spec/ortbConverter/schain_spec.js +33 -0
- package/test/spec/ortbConverter/userId_spec.js +21 -0
- package/test/spec/ortbConverter/usp_spec.js +15 -0
- package/test/spec/ortbConverter/video_spec.js +189 -0
- package/test/spec/unit/core/adapterManager_spec.js +102 -0
- package/test/spec/unit/core/targeting_spec.js +34 -0
- package/test/spec/unit/pbjs_api_spec.js +124 -45
- package/test/spec/utils_spec.js +45 -1
|
@@ -0,0 +1,854 @@
|
|
|
1
|
+
import {
|
|
2
|
+
SETUP_COMPLETE, SETUP_FAILED, DESTROYED,
|
|
3
|
+
PLAYLIST, PLAYBACK_REQUEST, CONTENT_LOADED, PLAY, PAUSE, TIME, SEEK_START, SEEK_END, MUTE, VOLUME, ERROR, COMPLETE,
|
|
4
|
+
FULLSCREEN, PLAYER_RESIZE,
|
|
5
|
+
AD_REQUEST, AD_IMPRESSION, AD_TIME, AD_COMPLETE, AD_SKIPPED, AD_CLICK, AD_STARTED, AD_ERROR, AD_LOADED, AD_PLAY, AD_PAUSE
|
|
6
|
+
} from '../libraries/video/constants/events.js';
|
|
7
|
+
// missing events: , AD_BREAK_START, , AD_BREAK_END, VIEWABLE, BUFFER, CAST, PLAYLIST_COMPLETE, RENDITION_UPDATE, PLAY_ATTEMPT_FAILED, AUTOSTART_BLOCKED
|
|
8
|
+
import {
|
|
9
|
+
PROTOCOLS, API_FRAMEWORKS, VIDEO_MIME_TYPE, PLAYBACK_METHODS, PLACEMENT, VPAID_MIME_TYPE, AD_POSITION, PLAYBACK_END
|
|
10
|
+
} from '../libraries/video/constants/ortb.js';
|
|
11
|
+
import { VIDEO_JS_VENDOR } from '../libraries/video/constants/vendorCodes.js';
|
|
12
|
+
import { submodule } from '../src/hook.js';
|
|
13
|
+
import stateFactory from '../libraries/video/shared/state.js';
|
|
14
|
+
import { PLAYBACK_MODE } from '../libraries/video/constants/enums.js';
|
|
15
|
+
import { getEventHandler } from '../libraries/video/shared/eventHandler.js';
|
|
16
|
+
|
|
17
|
+
/*
|
|
18
|
+
Plugins of interest:
|
|
19
|
+
https://www.npmjs.com/package/videojs-chromecast
|
|
20
|
+
https://www.npmjs.com/package/@silvermine/videojs-airplay
|
|
21
|
+
https://www.npmjs.com/package/videojs-airplay
|
|
22
|
+
https://www.npmjs.com/package/@silvermine/videojs-chromecast
|
|
23
|
+
https://www.npmjs.com/package/videojs-ima
|
|
24
|
+
https://github.com/googleads/videojs-ima
|
|
25
|
+
https://github.com/videojs/videojs-playlist
|
|
26
|
+
https://github.com/videojs/videojs-contrib-ads
|
|
27
|
+
https://github.com/videojs/videojs-errors
|
|
28
|
+
https://github.com/videojs/videojs-overlay
|
|
29
|
+
https://github.com/videojs/videojs-playlist-ui
|
|
30
|
+
|
|
31
|
+
inspiration:
|
|
32
|
+
https://github.com/Conviva/conviva-js-videojs/blob/master/conviva-videojs-module.js
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
const setupFailMessage = 'Failed to instantiate the player';
|
|
36
|
+
const AD_MANAGER_EVENTS = [AD_LOADED, AD_STARTED, AD_IMPRESSION, AD_PLAY, AD_PAUSE, AD_TIME, AD_COMPLETE, AD_SKIPPED];
|
|
37
|
+
|
|
38
|
+
export function VideojsProvider(config, vjs_, adState_, timeState_, callbackStorage_, utils) {
|
|
39
|
+
let vjs = vjs_;
|
|
40
|
+
// Supplied callbacks are typically wrapped by handlers
|
|
41
|
+
// we use this dict to keep track of these pairings
|
|
42
|
+
const callbackToHandler = {};
|
|
43
|
+
|
|
44
|
+
const adState = adState_;
|
|
45
|
+
const timeState = timeState_;
|
|
46
|
+
let player = null;
|
|
47
|
+
let playerVersion = null;
|
|
48
|
+
let playerIsSetup = false;
|
|
49
|
+
const {playerConfig, divId} = config;
|
|
50
|
+
let isMuted;
|
|
51
|
+
let previousLastTimePosition = 0;
|
|
52
|
+
let lastTimePosition = 0;
|
|
53
|
+
|
|
54
|
+
let setupCompleteCallbacks = [];
|
|
55
|
+
let setupFailedCallbacks = [];
|
|
56
|
+
let setupFailedEventHandlers = [];
|
|
57
|
+
|
|
58
|
+
// TODO: test with older videojs versions
|
|
59
|
+
let minimumSupportedPlayerVersion = '7.17.0';
|
|
60
|
+
|
|
61
|
+
function init() {
|
|
62
|
+
if (!vjs) {
|
|
63
|
+
triggerSetupFailure(-1, setupFailMessage + ': Videojs not present')
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
playerVersion = vjs.VERSION;
|
|
68
|
+
if (playerVersion < minimumSupportedPlayerVersion) {
|
|
69
|
+
triggerSetupFailure(-2, setupFailMessage + ': Videojs version not supported');
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (!document.getElementById(divId)) {
|
|
74
|
+
triggerSetupFailure(-3, setupFailMessage + ': No div found with id ' + divId);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const instantiatedPlayers = vjs.players;
|
|
79
|
+
if (instantiatedPlayers && instantiatedPlayers[divId]) {
|
|
80
|
+
// already instantiated
|
|
81
|
+
player = instantiatedPlayers[divId];
|
|
82
|
+
onReady();
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
setupPlayer(playerConfig);
|
|
87
|
+
|
|
88
|
+
if (!player) {
|
|
89
|
+
triggerSetupFailure(-4, setupFailMessage);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function getId() {
|
|
94
|
+
return divId;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function getOrtbVideo() {
|
|
98
|
+
if (!player) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
let playBackMethod = PLAYBACK_METHODS.CLICK_TO_PLAY;
|
|
103
|
+
// returns a boolean or a string with the autoplay strategy
|
|
104
|
+
const autoplay = player.autoplay();
|
|
105
|
+
const muted = player.muted() || autoplay === 'muted';
|
|
106
|
+
// check if autoplay is truthy since it may be a bool or string
|
|
107
|
+
if (autoplay) {
|
|
108
|
+
playBackMethod = muted ? PLAYBACK_METHODS.AUTOPLAY_MUTED : PLAYBACK_METHODS.AUTOPLAY;
|
|
109
|
+
}
|
|
110
|
+
const supportedMediaTypes = Object.values(VIDEO_MIME_TYPE).filter(
|
|
111
|
+
// Follows w3 spec https://www.w3.org/TR/2011/WD-html5-20110113/video.html#dom-navigator-canplaytype
|
|
112
|
+
type => player.canPlayType(type) !== ''
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
// IMA supports vpaid unless its expliclty turned off
|
|
116
|
+
// TODO: needs a reference to the imaOptions used at setup to determine if vpaid can be used
|
|
117
|
+
// if (imaOptions && imaOptions.vpaidMode !== 0) {
|
|
118
|
+
supportedMediaTypes.push(VPAID_MIME_TYPE);
|
|
119
|
+
// }
|
|
120
|
+
|
|
121
|
+
const video = {
|
|
122
|
+
mimes: supportedMediaTypes,
|
|
123
|
+
// Based on the protocol support provided by the videojs-ima plugin
|
|
124
|
+
// https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/compatibility
|
|
125
|
+
// Need to check for the plugins
|
|
126
|
+
protocols: [
|
|
127
|
+
PROTOCOLS.VAST_2_0,
|
|
128
|
+
],
|
|
129
|
+
api: [
|
|
130
|
+
API_FRAMEWORKS.VPAID_2_0 // TODO: needs a reference to the imaOptions used at setup to determine if vpaid can be used
|
|
131
|
+
],
|
|
132
|
+
// TODO: Make sure this returns dimensions in DIPS
|
|
133
|
+
h: player.currentHeight(),
|
|
134
|
+
w: player.currentWidth(),
|
|
135
|
+
// TODO: implement startdelay since its reccomend param
|
|
136
|
+
// both linearity forms are supported so the param is excluded
|
|
137
|
+
// sequence - TODO not yet supported
|
|
138
|
+
maxextended: -1,
|
|
139
|
+
boxingallowed: 1,
|
|
140
|
+
playbackmethod: [ playBackMethod ],
|
|
141
|
+
playbackend: PLAYBACK_END.VIDEO_COMPLETION,
|
|
142
|
+
// Per ortb 7.4 skip is omitted since neither the player nor ima plugin imposes a skip button, or a skipmin/max
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
// TODO: Determine placement may not be in stream if videojs is only used to serve ad content
|
|
146
|
+
// ~ Sort of resolved check if the player has a source to tell if the placement is instream
|
|
147
|
+
// Still cannot reliably check what type of placement the player is if its outstream
|
|
148
|
+
// i.e. we can't tell if its interstitial, in article, etc.
|
|
149
|
+
if (player.src()) {
|
|
150
|
+
video.placement = PLACEMENT.INSTREAM;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Placement according to IQG Guidelines 4.2.8
|
|
154
|
+
// https://cdn2.hubspot.net/hubfs/2848641/TrustworthyAccountabilityGroup_May2017/Docs/TAG-Inventory-Quality-Guidelines-v2_2-10-18-2016.pdf?t=1509469105938
|
|
155
|
+
const findPosition = vjs.dom.findPosition;
|
|
156
|
+
if (player.isFullscreen()) {
|
|
157
|
+
video.pos = AD_POSITION.FULL_SCREEN;
|
|
158
|
+
} else if (findPosition) {
|
|
159
|
+
video.pos = utils.getPositionCode(findPosition(player.el()));
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return video;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function getOrtbContent() {
|
|
166
|
+
if (!player) {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const content = {
|
|
171
|
+
// id:, TODO: find a suitable id for videojs sources
|
|
172
|
+
url: player.currentSrc()
|
|
173
|
+
};
|
|
174
|
+
// Only include length if player is ready
|
|
175
|
+
// player.readyState() returns a level of readiness from 0 to 4
|
|
176
|
+
// https://docs.videojs.com/player#readyState
|
|
177
|
+
if (player.readyState()) {
|
|
178
|
+
content.len = Math.round(player.duration());
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const mediaItem = utils.getMedia(player);
|
|
182
|
+
if (mediaItem) {
|
|
183
|
+
for (let param of ['id', 'title', 'description', 'album', 'artist']) {
|
|
184
|
+
if (mediaItem[param]) {
|
|
185
|
+
content[param] = mediaItem[param];
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const contentUrl = utils.getValidMediaUrl(mediaItem && mediaItem.src, player.src)
|
|
191
|
+
if (contentUrl) {
|
|
192
|
+
content.url = contentUrl;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return content;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Plugins to integrate: https://github.com/googleads/videojs-ima
|
|
199
|
+
function setAdTagUrl(adTagUrl, options) {
|
|
200
|
+
if (!player.ima || !adTagUrl) {
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
player.ima.changeAdTag(adTagUrl);
|
|
205
|
+
player.ima.requestAds();
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function onEvent(type, callback, payload) {
|
|
209
|
+
registerSetupListeners(type, callback, payload);
|
|
210
|
+
|
|
211
|
+
if (!player) {
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
player.ready(() => {
|
|
216
|
+
registerListeners(type, callback, payload);
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function registerSetupListeners(externalEventName, callback, basePayload) {
|
|
221
|
+
// no point in registering for setup failures if already setup.
|
|
222
|
+
if (playerIsSetup) {
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (externalEventName === SETUP_COMPLETE) {
|
|
227
|
+
setupCompleteCallbacks.push(callback);
|
|
228
|
+
} else if (externalEventName === SETUP_FAILED) {
|
|
229
|
+
setupFailedCallbacks.push(callback);
|
|
230
|
+
registerSetupErrorListener()
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function registerSetupErrorListener() {
|
|
235
|
+
if (!player) {
|
|
236
|
+
return
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const eventHandler = () => {
|
|
240
|
+
/*
|
|
241
|
+
Videojs has no specific setup error handler
|
|
242
|
+
so we imitate it by hooking to the general error
|
|
243
|
+
handler and checking to see if the player has been setup
|
|
244
|
+
*/
|
|
245
|
+
if (playerIsSetup) {
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const error = player.error();
|
|
250
|
+
triggerSetupFailure(error.code, error.message, error);
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
player.on(ERROR, eventHandler);
|
|
254
|
+
setupFailedEventHandlers.push(eventHandler)
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
function registerListeners(externalEventName, callback, basePayload) {
|
|
258
|
+
if (externalEventName === MUTE) {
|
|
259
|
+
const eventHandler = () => {
|
|
260
|
+
if (isMuted !== player.muted()) {
|
|
261
|
+
basePayload.mute = isMuted = !isMuted;
|
|
262
|
+
callback(externalEventName, basePayload);
|
|
263
|
+
}
|
|
264
|
+
};
|
|
265
|
+
player.on(utils.getVideojsEventName(VOLUME), eventHandler);
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
let getEventPayload;
|
|
270
|
+
|
|
271
|
+
switch (externalEventName) {
|
|
272
|
+
case PLAY:
|
|
273
|
+
case PAUSE:
|
|
274
|
+
case DESTROYED:
|
|
275
|
+
break;
|
|
276
|
+
|
|
277
|
+
case PLAYBACK_REQUEST:
|
|
278
|
+
getEventPayload = e => ({ playReason: 'unknown' });
|
|
279
|
+
break;
|
|
280
|
+
|
|
281
|
+
case AD_REQUEST:
|
|
282
|
+
getEventPayload = e => {
|
|
283
|
+
const adTagUrl = e.AdsRequest.adTagUrl;
|
|
284
|
+
adState.updateState({ adTagUrl });
|
|
285
|
+
return { adTagUrl };
|
|
286
|
+
};
|
|
287
|
+
break
|
|
288
|
+
|
|
289
|
+
case AD_LOADED:
|
|
290
|
+
getEventPayload = (e) => {
|
|
291
|
+
const imaAd = e.getAdData && e.getAdData();
|
|
292
|
+
adState.updateForEvent(imaAd);
|
|
293
|
+
timeState.clearState();
|
|
294
|
+
return adState.getState();
|
|
295
|
+
};
|
|
296
|
+
break
|
|
297
|
+
|
|
298
|
+
case AD_STARTED:
|
|
299
|
+
case AD_PLAY:
|
|
300
|
+
case AD_PAUSE:
|
|
301
|
+
getEventPayload = () => adState.getState();
|
|
302
|
+
break
|
|
303
|
+
|
|
304
|
+
case AD_IMPRESSION:
|
|
305
|
+
case AD_CLICK:
|
|
306
|
+
getEventPayload = () => Object.assign({}, adState.getState(), timeState.getState());
|
|
307
|
+
break
|
|
308
|
+
|
|
309
|
+
case AD_TIME:
|
|
310
|
+
getEventPayload = (e) => {
|
|
311
|
+
const adTimeEvent = e && e.getAdData && e.getAdData();
|
|
312
|
+
timeState.updateForTimeEvent(adTimeEvent);
|
|
313
|
+
return Object.assign({}, adState.getState(), timeState.getState());
|
|
314
|
+
};
|
|
315
|
+
break
|
|
316
|
+
|
|
317
|
+
case AD_COMPLETE:
|
|
318
|
+
getEventPayload = () => {
|
|
319
|
+
const currentState = adState.getState();
|
|
320
|
+
adState.clearState();
|
|
321
|
+
return currentState;
|
|
322
|
+
};
|
|
323
|
+
break
|
|
324
|
+
|
|
325
|
+
case AD_SKIPPED:
|
|
326
|
+
getEventPayload = () => {
|
|
327
|
+
const currentState = Object.assign({}, adState.getState(), timeState.getState());
|
|
328
|
+
adState.clearState();
|
|
329
|
+
return currentState;
|
|
330
|
+
};
|
|
331
|
+
break
|
|
332
|
+
|
|
333
|
+
case AD_ERROR:
|
|
334
|
+
getEventPayload = e => {
|
|
335
|
+
const imaAdError = e.data && e.data.AdError;
|
|
336
|
+
const extraPayload = Object.assign({
|
|
337
|
+
playerErrorCode: imaAdError.getErrorCode(),
|
|
338
|
+
vastErrorCode: imaAdError.getVastErrorCode(),
|
|
339
|
+
errorMessage: imaAdError.getMessage(),
|
|
340
|
+
sourceError: imaAdError.getInnerError()
|
|
341
|
+
// timeout
|
|
342
|
+
}, adState.getState(), timeState.getState());
|
|
343
|
+
adState.clearState();
|
|
344
|
+
return extraPayload;
|
|
345
|
+
};
|
|
346
|
+
break
|
|
347
|
+
|
|
348
|
+
case PLAYLIST:
|
|
349
|
+
getEventPayload = e => ({
|
|
350
|
+
playlistItemCount: utils.getPlaylistCount(player),
|
|
351
|
+
autostart: player.autoplay()
|
|
352
|
+
});
|
|
353
|
+
break
|
|
354
|
+
|
|
355
|
+
case CONTENT_LOADED:
|
|
356
|
+
getEventPayload = e => {
|
|
357
|
+
const media = utils.getMedia(player);
|
|
358
|
+
const contentUrl = utils.getValidMediaUrl(media && media.src, player.src, e && e.target && e.target.currentSrc)
|
|
359
|
+
return {
|
|
360
|
+
contentId: media && media.id,
|
|
361
|
+
contentUrl,
|
|
362
|
+
title: media && media.title,
|
|
363
|
+
description: media && media.description,
|
|
364
|
+
playlistIndex: utils.getCurrentPlaylistIndex(player),
|
|
365
|
+
contentTags: media && media.contentTags
|
|
366
|
+
};
|
|
367
|
+
};
|
|
368
|
+
break;
|
|
369
|
+
|
|
370
|
+
case TIME:
|
|
371
|
+
// TODO: might want to check seeking() and/or scrubbing()
|
|
372
|
+
getEventPayload = e => {
|
|
373
|
+
previousLastTimePosition = lastTimePosition;
|
|
374
|
+
const currentTime = player.currentTime();
|
|
375
|
+
const duration = player.duration();
|
|
376
|
+
timeState.updateForTimeEvent({ currentTime, duration });
|
|
377
|
+
lastTimePosition = currentTime;
|
|
378
|
+
return {
|
|
379
|
+
position: lastTimePosition,
|
|
380
|
+
duration
|
|
381
|
+
};
|
|
382
|
+
};
|
|
383
|
+
break;
|
|
384
|
+
|
|
385
|
+
case SEEK_START:
|
|
386
|
+
getEventPayload = e => {
|
|
387
|
+
return {
|
|
388
|
+
position: previousLastTimePosition,
|
|
389
|
+
destination: player.currentTime(),
|
|
390
|
+
duration: player.duration()
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
break;
|
|
394
|
+
|
|
395
|
+
case SEEK_END:
|
|
396
|
+
getEventPayload = () => ({
|
|
397
|
+
position: player.currentTime(),
|
|
398
|
+
duration: player.duration()
|
|
399
|
+
});
|
|
400
|
+
break;
|
|
401
|
+
|
|
402
|
+
case VOLUME:
|
|
403
|
+
getEventPayload = e => ({ volumePercentage: player.volume() * 100 });
|
|
404
|
+
break;
|
|
405
|
+
|
|
406
|
+
case ERROR:
|
|
407
|
+
getEventPayload = e => {
|
|
408
|
+
const error = player.error();
|
|
409
|
+
return {
|
|
410
|
+
sourceError: error,
|
|
411
|
+
errorCode: error.code,
|
|
412
|
+
errorMessage: error.message,
|
|
413
|
+
};
|
|
414
|
+
};
|
|
415
|
+
break;
|
|
416
|
+
|
|
417
|
+
case COMPLETE:
|
|
418
|
+
getEventPayload = e => {
|
|
419
|
+
previousLastTimePosition = lastTimePosition = 0;
|
|
420
|
+
timeState.clearState();
|
|
421
|
+
};
|
|
422
|
+
break;
|
|
423
|
+
|
|
424
|
+
case FULLSCREEN:
|
|
425
|
+
getEventPayload = e => ({ fullscreen: player.isFullscreen() });
|
|
426
|
+
break;
|
|
427
|
+
|
|
428
|
+
case PLAYER_RESIZE:
|
|
429
|
+
getEventPayload = e => ({
|
|
430
|
+
height: player.currentHeight(),
|
|
431
|
+
width: player.currentWidth(),
|
|
432
|
+
});
|
|
433
|
+
break;
|
|
434
|
+
|
|
435
|
+
default:
|
|
436
|
+
return;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
const eventHandler = getEventHandler(externalEventName, callback, basePayload, getEventPayload);
|
|
440
|
+
|
|
441
|
+
if (externalEventName === PLAYLIST) {
|
|
442
|
+
registerPlaylistEventListener(eventHandler);
|
|
443
|
+
return;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
const videojsEventName = utils.getVideojsEventName(externalEventName);
|
|
447
|
+
|
|
448
|
+
if (AD_MANAGER_EVENTS.includes(externalEventName)) {
|
|
449
|
+
player.on('ads-manager', () => player.ima.addEventListener(videojsEventName, eventHandler));
|
|
450
|
+
} else {
|
|
451
|
+
player.on(videojsEventName, eventHandler);
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
function registerPlaylistEventListener(eventHandler) {
|
|
456
|
+
if (player.playlist) {
|
|
457
|
+
// force a playlist event on first item load
|
|
458
|
+
player.one('loadstart', eventHandler);
|
|
459
|
+
player.on('playlistchange', eventHandler);
|
|
460
|
+
} else {
|
|
461
|
+
// When playlist plugin is not used, treat each media item as a single item playlist
|
|
462
|
+
player.on('loadstart', eventHandler);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
function offEvent(event, callback) {
|
|
467
|
+
const videojsEvent = utils.getVideojsEventName(event)
|
|
468
|
+
if (!callback) {
|
|
469
|
+
player.off(videojsEvent);
|
|
470
|
+
return;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
const eventHandler = callbackToHandler[event];// callbackStorage.getCallback(event, callback);
|
|
474
|
+
if (eventHandler) {
|
|
475
|
+
player.off(videojsEvent, eventHandler);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
function destroy() {
|
|
480
|
+
if (!player) {
|
|
481
|
+
return;
|
|
482
|
+
}
|
|
483
|
+
player.remove();
|
|
484
|
+
player = null;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
return {
|
|
488
|
+
init,
|
|
489
|
+
getId,
|
|
490
|
+
getOrtbVideo,
|
|
491
|
+
getOrtbContent,
|
|
492
|
+
setAdTagUrl,
|
|
493
|
+
onEvent,
|
|
494
|
+
offEvent,
|
|
495
|
+
destroy
|
|
496
|
+
};
|
|
497
|
+
|
|
498
|
+
function setupPlayer(config) {
|
|
499
|
+
const setupConfig = utils.getSetupConfig(config);
|
|
500
|
+
player = vjs(divId, setupConfig, onReady);
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
function onReady() {
|
|
504
|
+
try {
|
|
505
|
+
setupAds();
|
|
506
|
+
} catch (e) {
|
|
507
|
+
triggerSetupFailure(-5, e.message);
|
|
508
|
+
return;
|
|
509
|
+
}
|
|
510
|
+
triggerSetupComplete();
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
// TODO: consider supporting https://www.npmjs.com/package/videojs-vast-vpaid as well
|
|
514
|
+
function setupAds() {
|
|
515
|
+
if (!player.ima) {
|
|
516
|
+
throw new Error(setupFailMessage + ': ima plugin is missing');
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
if (typeof player.ima !== 'function') {
|
|
520
|
+
// when player.ima is already instantiated, it is an object. Early abort if already instantiated.
|
|
521
|
+
return;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
const adConfig = utils.getAdConfig(config);
|
|
525
|
+
player.ima(adConfig);
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
function triggerSetupFailure(errorCode, msg, sourceError) {
|
|
529
|
+
const payload = {
|
|
530
|
+
divId,
|
|
531
|
+
playerVersion,
|
|
532
|
+
type: SETUP_FAILED,
|
|
533
|
+
errorCode,
|
|
534
|
+
errorMessage: msg,
|
|
535
|
+
sourceError: sourceError
|
|
536
|
+
};
|
|
537
|
+
setupFailedCallbacks.forEach(setupFailedCallback => setupFailedCallback(SETUP_FAILED, payload));
|
|
538
|
+
setupFailedCallbacks = [];
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
function triggerSetupComplete() {
|
|
542
|
+
playerIsSetup = true;
|
|
543
|
+
const payload = {
|
|
544
|
+
divId,
|
|
545
|
+
playerVersion,
|
|
546
|
+
type: SETUP_COMPLETE,
|
|
547
|
+
};
|
|
548
|
+
|
|
549
|
+
setupCompleteCallbacks.forEach(callback => callback(SETUP_COMPLETE, payload));
|
|
550
|
+
setupCompleteCallbacks = [];
|
|
551
|
+
|
|
552
|
+
isMuted = player.muted();
|
|
553
|
+
|
|
554
|
+
setupFailedEventHandlers.forEach(eventHandler => player.off('error', eventHandler));
|
|
555
|
+
setupFailedEventHandlers = [];
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
export const utils = {
|
|
560
|
+
getSetupConfig: function (config) {
|
|
561
|
+
if (!config) {
|
|
562
|
+
return;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
const params = config.params || {};
|
|
566
|
+
const videojsConfig = params.vendorConfig || {};
|
|
567
|
+
|
|
568
|
+
if (videojsConfig.autostart === undefined && config.autostart !== undefined) {
|
|
569
|
+
videojsConfig.autostart = config.autostart
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
if (videojsConfig.muted === undefined && config.mute !== undefined) {
|
|
573
|
+
videojsConfig.muted = config.mute;
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
return videojsConfig;
|
|
577
|
+
},
|
|
578
|
+
|
|
579
|
+
getAdConfig: function (config) {
|
|
580
|
+
const params = config && config.params;
|
|
581
|
+
if (!params) {
|
|
582
|
+
return {};
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
return params.adPluginConfig || {}; // TODO: add adPluginConfig to spec
|
|
586
|
+
},
|
|
587
|
+
|
|
588
|
+
getPositionCode: function({left, top, width, height}) {
|
|
589
|
+
const bottom = window.innerHeight - top - height;
|
|
590
|
+
const right = window.innerWidth - left - width;
|
|
591
|
+
|
|
592
|
+
if (left < 0 || right < 0 || top < 0) {
|
|
593
|
+
return AD_POSITION.UNKNOWN;
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
return bottom >= 0 ? AD_POSITION.ABOVE_THE_FOLD : AD_POSITION.BELOW_THE_FOLD;
|
|
597
|
+
},
|
|
598
|
+
|
|
599
|
+
getVideojsEventName: function(eventName) {
|
|
600
|
+
switch (eventName) {
|
|
601
|
+
case SETUP_COMPLETE:
|
|
602
|
+
return 'ready';
|
|
603
|
+
case SETUP_FAILED:
|
|
604
|
+
return 'error';
|
|
605
|
+
case DESTROYED:
|
|
606
|
+
return 'dispose';
|
|
607
|
+
case AD_REQUEST:
|
|
608
|
+
return 'ads-request';
|
|
609
|
+
case AD_LOADED:
|
|
610
|
+
return 'loaded'
|
|
611
|
+
case AD_STARTED:
|
|
612
|
+
return 'start';
|
|
613
|
+
case AD_IMPRESSION:
|
|
614
|
+
return 'impression';
|
|
615
|
+
case AD_PLAY:
|
|
616
|
+
return 'resume'
|
|
617
|
+
case AD_PAUSE:
|
|
618
|
+
return PAUSE;
|
|
619
|
+
case AD_TIME:
|
|
620
|
+
return 'adProgress';
|
|
621
|
+
case AD_CLICK:
|
|
622
|
+
return 'click';
|
|
623
|
+
case AD_COMPLETE:
|
|
624
|
+
return COMPLETE;
|
|
625
|
+
case AD_SKIPPED:
|
|
626
|
+
return 'skip';
|
|
627
|
+
case AD_ERROR:
|
|
628
|
+
return 'adserror';
|
|
629
|
+
case CONTENT_LOADED:
|
|
630
|
+
return 'loadstart';
|
|
631
|
+
case PLAY:
|
|
632
|
+
return PLAY + 'ing';
|
|
633
|
+
case PLAYBACK_REQUEST:
|
|
634
|
+
return PLAY;
|
|
635
|
+
case SEEK_START:
|
|
636
|
+
return 'seeking';
|
|
637
|
+
case SEEK_END:
|
|
638
|
+
return 'seeked';
|
|
639
|
+
case TIME:
|
|
640
|
+
return TIME + 'update';
|
|
641
|
+
case VOLUME:
|
|
642
|
+
return VOLUME + 'change';
|
|
643
|
+
case MUTE:
|
|
644
|
+
return MUTE + 'change';
|
|
645
|
+
case PLAYER_RESIZE:
|
|
646
|
+
return 'playerresize';
|
|
647
|
+
case FULLSCREEN:
|
|
648
|
+
return FULLSCREEN + 'change';
|
|
649
|
+
case COMPLETE:
|
|
650
|
+
return 'ended';
|
|
651
|
+
default:
|
|
652
|
+
return eventName;
|
|
653
|
+
}
|
|
654
|
+
/*
|
|
655
|
+
The following video.js events might map to an event in our spec
|
|
656
|
+
'loadstart',
|
|
657
|
+
'progress', buffer load ?
|
|
658
|
+
'suspend',
|
|
659
|
+
'abort',
|
|
660
|
+
'error',
|
|
661
|
+
'emptied',
|
|
662
|
+
'stalled',
|
|
663
|
+
'loadedmetadata', meta
|
|
664
|
+
'loadeddata', meta
|
|
665
|
+
'canplay',
|
|
666
|
+
'canplaythrough',
|
|
667
|
+
'waiting', buffer?
|
|
668
|
+
'durationchange', meta-duration
|
|
669
|
+
'ratechange',
|
|
670
|
+
*/
|
|
671
|
+
},
|
|
672
|
+
|
|
673
|
+
getMedia: function(player) {
|
|
674
|
+
const playlistItem = this.getCurrentPlaylistItem(player);
|
|
675
|
+
if (playlistItem) {
|
|
676
|
+
return playlistItem.sources[0];
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
return player.getMedia();
|
|
680
|
+
},
|
|
681
|
+
|
|
682
|
+
getValidMediaUrl: function(mediaSrc, playerSrc, eventTargetSrc) {
|
|
683
|
+
return this.getMediaUrl(mediaSrc) || this.getMediaUrl(playerSrc) || this.getMediaUrl(eventTargetSrc);
|
|
684
|
+
},
|
|
685
|
+
|
|
686
|
+
getMediaUrl: function(source) {
|
|
687
|
+
if (!source) {
|
|
688
|
+
return;
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
if (Array.isArray(source) && source.length) {
|
|
692
|
+
return this.parseSource(source[0]);
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
return this.parseSource(source)
|
|
696
|
+
},
|
|
697
|
+
|
|
698
|
+
parseSource: function (source) {
|
|
699
|
+
const type = typeof source;
|
|
700
|
+
if (type === 'string') {
|
|
701
|
+
return source;
|
|
702
|
+
} else if (type === 'object') {
|
|
703
|
+
return source.src;
|
|
704
|
+
}
|
|
705
|
+
},
|
|
706
|
+
|
|
707
|
+
getPlaylistCount: function (player) {
|
|
708
|
+
const playlist = player.playlist; // has playlist plugin
|
|
709
|
+
if (!playlist) {
|
|
710
|
+
return 1;
|
|
711
|
+
}
|
|
712
|
+
return playlist.lastIndex && playlist.lastIndex() + 1;
|
|
713
|
+
},
|
|
714
|
+
|
|
715
|
+
getCurrentPlaylistIndex: function (player) {
|
|
716
|
+
const playlist = player.playlist; // has playlist plugin
|
|
717
|
+
if (!playlist) {
|
|
718
|
+
return 0;
|
|
719
|
+
}
|
|
720
|
+
return playlist.currentIndex && playlist.currentIndex();
|
|
721
|
+
},
|
|
722
|
+
|
|
723
|
+
getCurrentPlaylistItem: function(player) {
|
|
724
|
+
const playlist = player.playlist; // has playlist plugin
|
|
725
|
+
if (!playlist) {
|
|
726
|
+
return;
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
const currentIndex = this.getCurrentPlaylistIndex(player);
|
|
730
|
+
if (!currentIndex) {
|
|
731
|
+
return
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
const item = playlist()[currentIndex];
|
|
735
|
+
return item;
|
|
736
|
+
}
|
|
737
|
+
};
|
|
738
|
+
|
|
739
|
+
const videojsSubmoduleFactory = function (config) {
|
|
740
|
+
const adState = adStateFactory();
|
|
741
|
+
const timeState = timeStateFactory();
|
|
742
|
+
const callbackStorage = null;
|
|
743
|
+
// videojs factory is stored to window by default
|
|
744
|
+
const vjs = window.videojs;
|
|
745
|
+
return VideojsProvider(config, vjs, adState, timeState, callbackStorage, utils);
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
videojsSubmoduleFactory.vendorCode = VIDEO_JS_VENDOR;
|
|
749
|
+
submodule('video', videojsSubmoduleFactory);
|
|
750
|
+
export default videojsSubmoduleFactory;
|
|
751
|
+
|
|
752
|
+
// STATE
|
|
753
|
+
|
|
754
|
+
/**
|
|
755
|
+
* @returns {State}
|
|
756
|
+
*/
|
|
757
|
+
export function adStateFactory() {
|
|
758
|
+
const adState = Object.assign({}, stateFactory());
|
|
759
|
+
|
|
760
|
+
function updateForEvent(event) {
|
|
761
|
+
if (!event) {
|
|
762
|
+
return;
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
const skippable = event.skippable;
|
|
766
|
+
// TODO: possibly can check traffickingParameters to determine if winning bid is passed
|
|
767
|
+
const updates = {
|
|
768
|
+
adId: event.adId,
|
|
769
|
+
adServer: event.adSystem,
|
|
770
|
+
advertiserName: event.advertiserName,
|
|
771
|
+
redirectUrl: event.clickThroughUrl,
|
|
772
|
+
creativeId: event.creativeId || event.creativeAdId,
|
|
773
|
+
dealId: event.dealId,
|
|
774
|
+
adDescription: event.description,
|
|
775
|
+
linear: event.linear,
|
|
776
|
+
creativeUrl: event.mediaUrl,
|
|
777
|
+
adTitle: event.title,
|
|
778
|
+
universalAdId: event.universalAdIdValue,
|
|
779
|
+
creativeType: event.contentType,
|
|
780
|
+
wrapperAdIds: event.adWrapperIds,
|
|
781
|
+
skip: skippable ? 1 : 0,
|
|
782
|
+
// missing fields:
|
|
783
|
+
// loadTime
|
|
784
|
+
// advertiserId - TODO: does this even exist ? If not, remove from spec
|
|
785
|
+
// vastVersion
|
|
786
|
+
// adCategories
|
|
787
|
+
// campaignId
|
|
788
|
+
// waterfallIndex
|
|
789
|
+
// waterfallCount
|
|
790
|
+
// skipmin
|
|
791
|
+
// adTagUrl - for now, only has request ad tag
|
|
792
|
+
// adPlacementType
|
|
793
|
+
};
|
|
794
|
+
|
|
795
|
+
const adPodInfo = event.adPodInfo;
|
|
796
|
+
if (adPodInfo && adPodInfo.podIndex > -1) {
|
|
797
|
+
updates.adPodCount = adPodInfo.totalAds;
|
|
798
|
+
updates.adPodIndex = adPodInfo.adPosition - 1; // Per IMA docs, adPosition is 1 based.
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
if (adPodInfo && adPodInfo.timeOffset) {
|
|
802
|
+
switch (adPodInfo.timeOffset) {
|
|
803
|
+
case -1:
|
|
804
|
+
updates.offset = 'post';
|
|
805
|
+
break
|
|
806
|
+
|
|
807
|
+
case 0:
|
|
808
|
+
// TODO: Defaults to 0 if this ad is not part of a pod, or the pod is not part of an ad playlist. - need to check if loaded dynamically and pass last content time update
|
|
809
|
+
updates.offset = 'pre';
|
|
810
|
+
break
|
|
811
|
+
|
|
812
|
+
default:
|
|
813
|
+
updates.offset = '' + adPodInfo.timeOffset;
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
if (skippable) {
|
|
818
|
+
updates.skipafter = event.skipTimeOffset;
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
this.updateState(updates);
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
adState.updateForEvent = updateForEvent;
|
|
825
|
+
|
|
826
|
+
return adState;
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
export function timeStateFactory() {
|
|
830
|
+
const timeState = Object.assign({}, stateFactory());
|
|
831
|
+
|
|
832
|
+
function updateForTimeEvent(event) {
|
|
833
|
+
const { currentTime, duration } = event;
|
|
834
|
+
this.updateState({
|
|
835
|
+
time: currentTime,
|
|
836
|
+
duration,
|
|
837
|
+
playbackMode: getPlaybackMode(duration)
|
|
838
|
+
});
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
timeState.updateForTimeEvent = updateForTimeEvent;
|
|
842
|
+
|
|
843
|
+
function getPlaybackMode(duration) {
|
|
844
|
+
if (duration > 0) {
|
|
845
|
+
return PLAYBACK_MODE.VOD;
|
|
846
|
+
} else if (duration < 0) {
|
|
847
|
+
return PLAYBACK_MODE.DVR;
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
return PLAYBACK_MODE.LIVE;
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
return timeState;
|
|
854
|
+
}
|