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.
Files changed (314) hide show
  1. package/dist/33acrossBidAdapter.js +1 -1
  2. package/dist/aaxBlockmeterRtdProvider.js +1 -0
  3. package/dist/adagioBidAdapter.js +1 -1
  4. package/dist/adbookpspBidAdapter.js +1 -1
  5. package/dist/adgenerationBidAdapter.js +1 -1
  6. package/dist/admaticBidAdapter.js +1 -0
  7. package/dist/adrelevantisBidAdapter.js +1 -1
  8. package/dist/adtrgtmeBidAdapter.js +1 -1
  9. package/dist/adxcgBidAdapter.js +1 -1
  10. package/dist/adyoulikeBidAdapter.js +1 -1
  11. package/dist/ajaBidAdapter.js +1 -1
  12. package/dist/amxBidAdapter.js +1 -1
  13. package/dist/amxIdSystem.js +1 -1
  14. package/dist/analyticsAdapter.js +1 -1
  15. package/dist/appierAnalyticsAdapter.js +1 -1
  16. package/dist/appnexusBidAdapter.js +1 -1
  17. package/dist/asoBidAdapter.js +1 -1
  18. package/dist/audiencerunBidAdapter.js +1 -1
  19. package/dist/axonixBidAdapter.js +1 -1
  20. package/dist/bidViewability.js +1 -1
  21. package/dist/bidViewabilityIO.js +1 -1
  22. package/dist/bidglassBidAdapter.js +1 -1
  23. package/dist/big-richmediaBidAdapter.js +1 -1
  24. package/dist/bluebillywigBidAdapter.js +1 -1
  25. package/dist/bridgewellBidAdapter.js +1 -1
  26. package/dist/brightMountainMediaBidAdapter.js +1 -1
  27. package/dist/browsiRtdProvider.js +1 -1
  28. package/dist/carodaBidAdapter.js +1 -1
  29. package/dist/chtnwBidAdapter.js +1 -0
  30. package/dist/cleanioRtdProvider.js +1 -1
  31. package/dist/concertBidAdapter.js +1 -1
  32. package/dist/connectIdSystem.js +1 -1
  33. package/dist/connectadBidAdapter.js +1 -1
  34. package/dist/consentManagement.js +1 -1
  35. package/dist/consentManagementUsp.js +1 -1
  36. package/dist/consumableBidAdapter.js +1 -1
  37. package/dist/conversantBidAdapter.js +1 -1
  38. package/dist/craftBidAdapter.js +1 -1
  39. package/dist/criteoBidAdapter.js +1 -1
  40. package/dist/currency.js +1 -1
  41. package/dist/dependencies.json +19 -0
  42. package/dist/dfpAdServerVideo.js +1 -1
  43. package/dist/dgkeywordRtdProvider.js +1 -1
  44. package/dist/dspxBidAdapter.js +1 -1
  45. package/dist/eplanningBidAdapter.js +1 -1
  46. package/dist/finativeBidAdapter.js +1 -1
  47. package/dist/gdprEnforcement.js +1 -1
  48. package/dist/glimpseBidAdapter.js +1 -1
  49. package/dist/gmosspBidAdapter.js +1 -1
  50. package/dist/goldbachBidAdapter.js +1 -1
  51. package/dist/googleAnalyticsAdapter.js +1 -1
  52. package/dist/gridBidAdapter.js +1 -1
  53. package/dist/gridNMBidAdapter.js +1 -1
  54. package/dist/growthCodeIdSystem.js +1 -1
  55. package/dist/gumgumBidAdapter.js +1 -1
  56. package/dist/h12mediaBidAdapter.js +1 -1
  57. package/dist/id5AnalyticsAdapter.js +1 -1
  58. package/dist/id5IdSystem.js +1 -1
  59. package/dist/impactifyBidAdapter.js +1 -1
  60. package/dist/improvedigitalBidAdapter.js +1 -1
  61. package/dist/inmarBidAdapter.js +1 -1
  62. package/dist/insticatorBidAdapter.js +1 -1
  63. package/dist/instreamTracking.js +1 -1
  64. package/dist/ixBidAdapter.js +1 -1
  65. package/dist/jixieBidAdapter.js +1 -1
  66. package/dist/justpremiumBidAdapter.js +1 -1
  67. package/dist/jwplayerVideoProvider.js +1 -0
  68. package/dist/kargoBidAdapter.js +1 -1
  69. package/dist/konduitAnalyticsAdapter.js +1 -1
  70. package/dist/kueezBidAdapter.js +1 -1
  71. package/dist/kueezRtbBidAdapter.js +1 -0
  72. package/dist/lassoBidAdapter.js +1 -1
  73. package/dist/lifestreetBidAdapter.js +1 -1
  74. package/dist/liveyieldAnalyticsAdapter.js +1 -1
  75. package/dist/logicadBidAdapter.js +1 -1
  76. package/dist/loglyliftBidAdapter.js +1 -1
  77. package/dist/magniteAnalyticsAdapter.js +1 -1
  78. package/dist/malltvAnalyticsAdapter.js +1 -1
  79. package/dist/marsmediaBidAdapter.js +1 -1
  80. package/dist/mediafuseBidAdapter.js +1 -1
  81. package/dist/mediakeysBidAdapter.js +1 -1
  82. package/dist/mediasquareBidAdapter.js +1 -1
  83. package/dist/mgidBidAdapter.js +1 -1
  84. package/dist/mgidRtdProvider.js +1 -0
  85. package/dist/minutemediaBidAdapter.js +1 -1
  86. package/dist/multibid.js +1 -1
  87. package/dist/not-for-prod/prebid.js +153 -141
  88. package/dist/oguryBidAdapter.js +1 -1
  89. package/dist/onetagBidAdapter.js +1 -1
  90. package/dist/ooloAnalyticsAdapter.js +1 -1
  91. package/dist/openxOrtbBidAdapter.js +1 -1
  92. package/dist/ortbConverter.js +1 -0
  93. package/dist/outbrainBidAdapter.js +1 -1
  94. package/dist/oxxionRtdProvider.js +1 -0
  95. package/dist/parrableIdSystem.js +1 -1
  96. package/dist/pbsExtensions.js +1 -0
  97. package/dist/permutiveRtdProvider.js +1 -1
  98. package/dist/pixfutureBidAdapter.js +1 -1
  99. package/dist/prebid-core.js +1 -1
  100. package/dist/prebidServerBidAdapter.js +1 -1
  101. package/dist/priceFloors.js +1 -1
  102. package/dist/pubCommonId.js +1 -1
  103. package/dist/publinkIdSystem.js +1 -1
  104. package/dist/pubmaticBidAdapter.js +1 -1
  105. package/dist/pubwiseAnalyticsAdapter.js +1 -1
  106. package/dist/pxyzBidAdapter.js +1 -1
  107. package/dist/quantcastBidAdapter.js +1 -1
  108. package/dist/readpeakBidAdapter.js +1 -1
  109. package/dist/relaidoBidAdapter.js +1 -1
  110. package/dist/rhythmoneBidAdapter.js +1 -1
  111. package/dist/riseBidAdapter.js +1 -1
  112. package/dist/rtdModule.js +1 -1
  113. package/dist/rubiconAnalyticsAdapter.js +1 -1
  114. package/dist/rubiconBidAdapter.js +1 -1
  115. package/dist/schain.js +1 -1
  116. package/dist/seedingAllianceBidAdapter.js +1 -1
  117. package/dist/seedtagBidAdapter.js +1 -1
  118. package/dist/sharethroughAnalyticsAdapter.js +1 -1
  119. package/dist/sharethroughBidAdapter.js +1 -1
  120. package/dist/shinezBidAdapter.js +1 -1
  121. package/dist/smaatoBidAdapter.js +1 -1
  122. package/dist/smartadserverBidAdapter.js +1 -1
  123. package/dist/smartxBidAdapter.js +1 -1
  124. package/dist/smilewantedBidAdapter.js +1 -1
  125. package/dist/sonobiBidAdapter.js +1 -1
  126. package/dist/sovrnAnalyticsAdapter.js +1 -1
  127. package/dist/sovrnBidAdapter.js +1 -1
  128. package/dist/spotxBidAdapter.js +1 -1
  129. package/dist/sspBCBidAdapter.js +1 -1
  130. package/dist/sublimeBidAdapter.js +1 -1
  131. package/dist/synacormediaBidAdapter.js +1 -1
  132. package/dist/targetVideoBidAdapter.js +1 -1
  133. package/dist/teadsBidAdapter.js +1 -1
  134. package/dist/teadsIdSystem.js +1 -1
  135. package/dist/trionBidAdapter.js +1 -1
  136. package/dist/tripleliftBidAdapter.js +1 -1
  137. package/dist/ttdBidAdapter.js +1 -1
  138. package/dist/ucfunnelAnalyticsAdapter.js +1 -1
  139. package/dist/underdogmediaBidAdapter.js +1 -1
  140. package/dist/undertoneBidAdapter.js +1 -1
  141. package/dist/userId.js +1 -1
  142. package/dist/vidazooBidAdapter.js +1 -1
  143. package/dist/video.js +1 -0
  144. package/dist/videoModule.js +1 -0
  145. package/dist/videobyteBidAdapter.js +1 -1
  146. package/dist/videojsVideoProvider.js +1 -0
  147. package/dist/visxBidAdapter.js +1 -1
  148. package/dist/vuukleBidAdapter.js +1 -1
  149. package/dist/widespaceBidAdapter.js +1 -1
  150. package/dist/winrBidAdapter.js +1 -1
  151. package/dist/yahoosspBidAdapter.js +1 -1
  152. package/dist/yieldmoBidAdapter.js +1 -1
  153. package/dist/yieldoneAnalyticsAdapter.js +1 -1
  154. package/integrationExamples/gpt/mgidRtdProvider_example.html +143 -0
  155. package/integrationExamples/videoModule/jwplayer/bidMarkedAsUsed.html +98 -0
  156. package/integrationExamples/videoModule/jwplayer/bidRequestScheduling.html +89 -0
  157. package/integrationExamples/videoModule/jwplayer/eventListeners.html +244 -0
  158. package/integrationExamples/videoModule/jwplayer/gamAdServerMediation.html +122 -0
  159. package/integrationExamples/videoModule/jwplayer/mediaMetadata.html +80 -0
  160. package/integrationExamples/videoModule/jwplayer/playlist.html +122 -0
  161. package/integrationExamples/videoModule/videojs/bidMarkedAsUsed.html +126 -0
  162. package/integrationExamples/videoModule/videojs/bidRequestScheduling.html +132 -0
  163. package/integrationExamples/videoModule/videojs/eventListeners.html +238 -0
  164. package/integrationExamples/videoModule/videojs/gamAdServerMediation.html +138 -0
  165. package/integrationExamples/videoModule/videojs/mediaMetadata.html +103 -0
  166. package/integrationExamples/videoModule/videojs/playlist.html +151 -0
  167. package/libraries/ortbConverter/README.md +378 -0
  168. package/libraries/ortbConverter/converter.js +135 -0
  169. package/libraries/ortbConverter/lib/composer.js +43 -0
  170. package/libraries/ortbConverter/lib/mergeProcessors.js +9 -0
  171. package/libraries/ortbConverter/lib/sizes.js +14 -0
  172. package/libraries/ortbConverter/processors/banner.js +40 -0
  173. package/libraries/ortbConverter/processors/default.js +167 -0
  174. package/libraries/ortbConverter/processors/mediaType.js +21 -0
  175. package/libraries/ortbConverter/processors/native.js +37 -0
  176. package/libraries/ortbConverter/processors/video.js +66 -0
  177. package/libraries/pbsExtensions/pbsExtensions.js +12 -0
  178. package/libraries/pbsExtensions/processors/aliases.js +17 -0
  179. package/libraries/pbsExtensions/processors/mediaType.js +23 -0
  180. package/libraries/pbsExtensions/processors/params.js +22 -0
  181. package/libraries/pbsExtensions/processors/pbs.js +99 -0
  182. package/libraries/pbsExtensions/processors/requestExtPrebid.js +30 -0
  183. package/libraries/pbsExtensions/processors/video.js +23 -0
  184. package/libraries/video/constants/enums.js +5 -0
  185. package/libraries/video/constants/events.js +97 -0
  186. package/libraries/video/constants/ortb.js +169 -0
  187. package/libraries/video/constants/vendorCodes.js +6 -0
  188. package/libraries/video/shared/eventHandler.js +18 -0
  189. package/libraries/video/shared/parentModule.js +82 -0
  190. package/libraries/video/shared/state.js +47 -0
  191. package/libraries/video/shared/vastXmlBuilder.js +77 -0
  192. package/libraries/video/shared/vastXmlEditor.js +115 -0
  193. package/modules/.submodules.json +7 -1
  194. package/modules/aaxBlockmeterRtdProvider.js +59 -0
  195. package/modules/aaxBlockmeterRtdProvider.md +48 -0
  196. package/modules/admaticBidAdapter.js +147 -0
  197. package/modules/admaticBidAdapter.md +48 -0
  198. package/modules/amxBidAdapter.js +1 -0
  199. package/modules/appnexusBidAdapter.js +38 -1
  200. package/modules/chtnwBidAdapter.js +110 -0
  201. package/modules/chtnwBidAdapter.md +31 -0
  202. package/modules/concertBidAdapter.js +44 -2
  203. package/modules/connectIdSystem.js +36 -23
  204. package/modules/connectIdSystem.md +3 -2
  205. package/modules/consentManagement.js +22 -1
  206. package/modules/consentManagementUsp.js +29 -7
  207. package/modules/criteoBidAdapter.js +25 -5
  208. package/modules/currency.js +9 -0
  209. package/modules/dgkeywordRtdProvider.js +3 -3
  210. package/modules/gridNMBidAdapter.js +10 -14
  211. package/modules/growthCodeIdSystem.js +9 -5
  212. package/modules/gumgumBidAdapter.js +4 -0
  213. package/modules/improvedigitalBidAdapter.js +191 -470
  214. package/modules/ixBidAdapter.js +54 -71
  215. package/modules/jwplayerVideoProvider.js +929 -0
  216. package/modules/jwplayerVideoProvider.md +25 -0
  217. package/modules/kargoBidAdapter.js +1 -1
  218. package/modules/kueezRtbBidAdapter.js +278 -0
  219. package/modules/kueezRtbBidAdapter.md +35 -0
  220. package/modules/magniteAnalyticsAdapter.js +6 -1
  221. package/modules/mgidRtdProvider.js +190 -0
  222. package/modules/mgidRtdProvider.md +51 -0
  223. package/modules/multibid/index.js +12 -0
  224. package/modules/openxOrtbBidAdapter.js +120 -275
  225. package/modules/oxxionRtdProvider.js +119 -0
  226. package/modules/oxxionRtdProvider.md +48 -0
  227. package/modules/permutiveRtdProvider.js +2 -1
  228. package/modules/permutiveRtdProvider.md +36 -1
  229. package/modules/prebidServerBidAdapter/index.js +19 -716
  230. package/modules/prebidServerBidAdapter/ortbConverter.js +274 -0
  231. package/modules/priceFloors.js +73 -1
  232. package/modules/pubmaticBidAdapter.js +21 -29
  233. package/modules/rtdModule/index.js +22 -1
  234. package/modules/schain.js +24 -1
  235. package/modules/spotxBidAdapter.js +16 -15
  236. package/modules/synacormediaBidAdapter.js +1 -1
  237. package/modules/teadsIdSystem.js +5 -0
  238. package/modules/tripleliftBidAdapter.js +1 -1
  239. package/modules/userId/eids.js +3 -10
  240. package/modules/userId/index.js +64 -6
  241. package/modules/videoModule/addingSubmodule.md +521 -0
  242. package/modules/videoModule/coreVideo.js +234 -0
  243. package/modules/videoModule/gamAdServerSubmodule.js +27 -0
  244. package/modules/videoModule/index.js +244 -0
  245. package/modules/videoModule/videoImpressionVerifier.js +206 -0
  246. package/modules/videojsVideoProvider.js +854 -0
  247. package/modules/videojsVideoProvider.md +17 -0
  248. package/package.json +12 -8
  249. package/src/adRendering.js +1 -1
  250. package/src/adapterManager.js +56 -7
  251. package/src/adloader.js +3 -1
  252. package/src/auction.js +6 -1
  253. package/src/events.js +5 -1
  254. package/src/pbjsORTB.js +35 -0
  255. package/src/prebid.js +137 -112
  256. package/src/targeting.js +10 -2
  257. package/src/utils/currency.js +16 -0
  258. package/src/utils.js +21 -0
  259. package/test/spec/auctionmanager_spec.js +15 -0
  260. package/test/spec/modules/aaxBlockmeter_spec.js +58 -0
  261. package/test/spec/modules/admaticBidAdapter_spec.js +46 -0
  262. package/test/spec/modules/chtnwBidAdapter_spec.js +105 -0
  263. package/test/spec/modules/concertBidAdapter_spec.js +56 -0
  264. package/test/spec/modules/connectIdSystem_spec.js +175 -5
  265. package/test/spec/modules/consentManagementUsp_spec.js +64 -18
  266. package/test/spec/modules/criteoBidAdapter_spec.js +28 -0
  267. package/test/spec/modules/dgkeywordRtdProvider_spec.js +3 -3
  268. package/test/spec/modules/eids_spec.js +10 -7
  269. package/test/spec/modules/ftrackIdSystem_spec.js +34 -22
  270. package/test/spec/modules/gumgumBidAdapter_spec.js +15 -0
  271. package/test/spec/modules/improvedigitalBidAdapter_spec.js +231 -211
  272. package/test/spec/modules/ixBidAdapter_spec.js +412 -350
  273. package/test/spec/modules/kueezRtbBidAdapter_spec.js +396 -0
  274. package/test/spec/modules/magniteAnalyticsAdapter_spec.js +26 -0
  275. package/test/spec/modules/mgidRtdProvider_spec.js +366 -0
  276. package/test/spec/modules/openxOrtbBidAdapter_spec.js +77 -49
  277. package/test/spec/modules/oxxionRtdProvider_spec.js +142 -0
  278. package/test/spec/modules/permutiveRtdProvider_spec.js +64 -5
  279. package/test/spec/modules/prebidServerBidAdapter_spec.js +139 -137
  280. package/test/spec/modules/realTimeDataModule_spec.js +65 -0
  281. package/test/spec/modules/tripleliftBidAdapter_spec.js +14 -0
  282. package/test/spec/modules/userId_spec.js +67 -1
  283. package/test/spec/modules/videoModule/coreVideo_spec.js +98 -0
  284. package/test/spec/modules/videoModule/pbVideo_spec.js +362 -0
  285. package/test/spec/modules/videoModule/shared/parentModule_spec.js +73 -0
  286. package/test/spec/modules/videoModule/shared/state_spec.js +26 -0
  287. package/test/spec/modules/videoModule/shared/vastXmlBuilder_spec.js +103 -0
  288. package/test/spec/modules/videoModule/shared/vastXmlEditor_spec.js +209 -0
  289. package/test/spec/modules/videoModule/submodules/jwplayerVideoProvider_spec.js +846 -0
  290. package/test/spec/modules/videoModule/submodules/videojsVideoProvider_spec.js +391 -0
  291. package/test/spec/modules/videoModule/videoImpressionVerifier_spec.js +112 -0
  292. package/test/spec/ortbConverter/banner_spec.js +203 -0
  293. package/test/spec/ortbConverter/composer_spec.js +69 -0
  294. package/test/spec/ortbConverter/converter_spec.js +283 -0
  295. package/test/spec/ortbConverter/currency_spec.js +40 -0
  296. package/test/spec/ortbConverter/default_processors_spec.js +61 -0
  297. package/test/spec/ortbConverter/gdpr_spec.js +38 -0
  298. package/test/spec/ortbConverter/mediaTypes_spec.js +67 -0
  299. package/test/spec/ortbConverter/mergeProcessors_spec.js +59 -0
  300. package/test/spec/ortbConverter/multibid_spec.js +35 -0
  301. package/test/spec/ortbConverter/native_spec.js +95 -0
  302. package/test/spec/ortbConverter/pbjsORTB_spec.js +67 -0
  303. package/test/spec/ortbConverter/pbsExtensions/aliases_spec.js +57 -0
  304. package/test/spec/ortbConverter/pbsExtensions/params_spec.js +96 -0
  305. package/test/spec/ortbConverter/pbsExtensions/video_spec.js +52 -0
  306. package/test/spec/ortbConverter/priceFloors_spec.js +143 -0
  307. package/test/spec/ortbConverter/schain_spec.js +33 -0
  308. package/test/spec/ortbConverter/userId_spec.js +21 -0
  309. package/test/spec/ortbConverter/usp_spec.js +15 -0
  310. package/test/spec/ortbConverter/video_spec.js +189 -0
  311. package/test/spec/unit/core/adapterManager_spec.js +102 -0
  312. package/test/spec/unit/core/targeting_spec.js +34 -0
  313. package/test/spec/unit/pbjs_api_spec.js +124 -45
  314. 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
+ }