@gcorevideo/player 2.30.1 → 2.30.3
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/assets/audio-tracks/template.ejs +1 -1
- package/dist/core.js +1 -1
- package/dist/index.css +335 -335
- package/dist/index.embed.js +43 -13
- package/dist/index.js +69 -32
- package/lib/plugins/audio-selector/AudioTracks.d.ts +4 -0
- package/lib/plugins/audio-selector/AudioTracks.d.ts.map +1 -1
- package/lib/plugins/audio-selector/AudioTracks.js +42 -12
- package/lib/plugins/media-control/MediaControl.d.ts +1 -0
- package/lib/plugins/media-control/MediaControl.d.ts.map +1 -1
- package/lib/plugins/media-control/MediaControl.js +9 -1
- package/package.json +1 -1
- package/src/plugins/audio-selector/AudioTracks.ts +51 -16
- package/src/plugins/audio-selector/__tests__/__snapshots__/AudioTracks.test.ts.snap +9 -9
- package/src/plugins/media-control/MediaControl.ts +10 -1
- package/tsconfig.tsbuildinfo +1 -1
- package/assets/vast-ads/style.scss +0 -112
- package/lib/plugins/vast-ads/VastAds.d.ts +0 -74
- package/lib/plugins/vast-ads/VastAds.d.ts.map +0 -1
- package/lib/plugins/vast-ads/VastAds.js +0 -693
- package/lib/plugins/vast-ads/loaderxml.d.ts +0 -32
- package/lib/plugins/vast-ads/loaderxml.d.ts.map +0 -1
- package/lib/plugins/vast-ads/loaderxml.js +0 -229
- package/lib/plugins/vast-ads/roll.d.ts +0 -60
- package/lib/plugins/vast-ads/roll.d.ts.map +0 -1
- package/lib/plugins/vast-ads/roll.js +0 -421
- package/lib/plugins/vast-ads/rollmanager.d.ts +0 -62
- package/lib/plugins/vast-ads/rollmanager.d.ts.map +0 -1
- package/lib/plugins/vast-ads/rollmanager.js +0 -357
- package/lib/plugins/vast-ads/sctemanager.d.ts +0 -18
- package/lib/plugins/vast-ads/sctemanager.d.ts.map +0 -1
- package/lib/plugins/vast-ads/sctemanager.js +0 -117
- package/lib/plugins/vast-ads/types.d.ts +0 -12
- package/lib/plugins/vast-ads/types.d.ts.map +0 -1
- package/lib/plugins/vast-ads/types.js +0 -1
- package/lib/plugins/vast-ads/urlhandler.d.ts +0 -4
- package/lib/plugins/vast-ads/urlhandler.d.ts.map +0 -1
- package/lib/plugins/vast-ads/urlhandler.js +0 -30
- package/lib/plugins/vast-ads/xmlhttprequest.d.ts +0 -6
- package/lib/plugins/vast-ads/xmlhttprequest.d.ts.map +0 -1
- package/lib/plugins/vast-ads/xmlhttprequest.js +0 -40
- package/lib/plugins/vast-ads/xmlmerge.d.ts +0 -12
- package/lib/plugins/vast-ads/xmlmerge.d.ts.map +0 -1
- package/lib/plugins/vast-ads/xmlmerge.js +0 -83
- package/src/plugins/vast-ads/VastAds.ts +0 -919
- package/src/plugins/vast-ads/loaderxml.ts +0 -301
- package/src/plugins/vast-ads/roll.ts +0 -590
- package/src/plugins/vast-ads/rollmanager.ts +0 -447
- package/src/plugins/vast-ads/sctemanager.ts +0 -152
- package/src/plugins/vast-ads/types.ts +0 -20
- package/src/plugins/vast-ads/urlhandler.ts +0 -42
- package/src/plugins/vast-ads/xmlhttprequest.ts +0 -49
- package/src/plugins/vast-ads/xmlmerge.ts +0 -106
|
@@ -1,447 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
$,
|
|
3
|
-
Browser,
|
|
4
|
-
Container,
|
|
5
|
-
ContainerPlugin,
|
|
6
|
-
Core,
|
|
7
|
-
Events,
|
|
8
|
-
HTML5Video,
|
|
9
|
-
Log,
|
|
10
|
-
Playback,
|
|
11
|
-
UIContainerPlugin,
|
|
12
|
-
Utils,
|
|
13
|
-
} from '@clappr/core'
|
|
14
|
-
import { reportError } from '@gcorevideo/utils'
|
|
15
|
-
import assert from 'assert'
|
|
16
|
-
|
|
17
|
-
import LoaderXML from './loaderxml.js'
|
|
18
|
-
import Roll from './roll.js'
|
|
19
|
-
import { ZeptoResult } from '../../types.js'
|
|
20
|
-
import { AdRollDesc, AdRollItem, AdRollType, VastAdsOptions } from './types.js'
|
|
21
|
-
|
|
22
|
-
type CoreOptions = Record<string, unknown>
|
|
23
|
-
|
|
24
|
-
type ExtensionData = Record<string, unknown>
|
|
25
|
-
|
|
26
|
-
export default class RollManager extends Events {
|
|
27
|
-
private _allURLRequest = false
|
|
28
|
-
|
|
29
|
-
private _container: Container
|
|
30
|
-
private container: Container
|
|
31
|
-
|
|
32
|
-
private _options: CoreOptions
|
|
33
|
-
|
|
34
|
-
private vastAdsOptions: VastAdsOptions
|
|
35
|
-
|
|
36
|
-
private _playback: Playback
|
|
37
|
-
|
|
38
|
-
private _contentElement: HTMLMediaElement
|
|
39
|
-
|
|
40
|
-
private _posterPlugin: UIContainerPlugin
|
|
41
|
-
|
|
42
|
-
private _clickToPausePlugin: ContainerPlugin
|
|
43
|
-
|
|
44
|
-
private adTemplates: AdRollItem[] | null = null
|
|
45
|
-
|
|
46
|
-
// private _adDisplayContainer: HTMLElement | null = null;
|
|
47
|
-
|
|
48
|
-
private extension: ExtensionData | null = null
|
|
49
|
-
|
|
50
|
-
private firstRemaininTime = 0
|
|
51
|
-
|
|
52
|
-
private _imaContainer: HTMLElement | null = null
|
|
53
|
-
|
|
54
|
-
private isPlaying = false
|
|
55
|
-
|
|
56
|
-
private loadXML: LoaderXML | null = null
|
|
57
|
-
|
|
58
|
-
private _pr: number
|
|
59
|
-
|
|
60
|
-
private roll: Roll | null = null
|
|
61
|
-
|
|
62
|
-
constructor(
|
|
63
|
-
private core: Core,
|
|
64
|
-
private options: CoreOptions,
|
|
65
|
-
private $skipAd: ZeptoResult,
|
|
66
|
-
private $muteIcon: ZeptoResult,
|
|
67
|
-
private $areaClick: ZeptoResult,
|
|
68
|
-
private _adContainer: HTMLElement,
|
|
69
|
-
private type: AdRollType,
|
|
70
|
-
private countRoll: number,
|
|
71
|
-
private volume: number,
|
|
72
|
-
private prevVolume: number,
|
|
73
|
-
) {
|
|
74
|
-
super()
|
|
75
|
-
this._options = options
|
|
76
|
-
this.vastAdsOptions = this._options.vastAds as any
|
|
77
|
-
this.container = this.core.activeContainer
|
|
78
|
-
this._container = this.container
|
|
79
|
-
// this.countRoll = countRoll || 0;
|
|
80
|
-
this.$skipAd = $skipAd
|
|
81
|
-
this.type = type
|
|
82
|
-
this.$muteIcon = $muteIcon
|
|
83
|
-
this.$areaClick = $areaClick
|
|
84
|
-
this._playback = this.core.activePlayback
|
|
85
|
-
this._contentElement = this._playback.el as HTMLMediaElement
|
|
86
|
-
this._posterPlugin = this._container.getPlugin('poster')
|
|
87
|
-
this._clickToPausePlugin = this._container.getPlugin('click_to_pause')
|
|
88
|
-
this._adContainer = _adContainer
|
|
89
|
-
this._events = {}
|
|
90
|
-
this._pr = Math.floor(Math.random() * 1000000)
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
private initializeRoll({
|
|
94
|
-
xml,
|
|
95
|
-
url,
|
|
96
|
-
extension,
|
|
97
|
-
}: {
|
|
98
|
-
xml: any
|
|
99
|
-
url: string
|
|
100
|
-
extension: any
|
|
101
|
-
}) {
|
|
102
|
-
try {
|
|
103
|
-
this.roll = new Roll({
|
|
104
|
-
core: this.core,
|
|
105
|
-
$skipAd: this.$skipAd,
|
|
106
|
-
$muteIcon: this.$muteIcon,
|
|
107
|
-
$areaClick: this.$areaClick,
|
|
108
|
-
mute: !!this.options.mute,
|
|
109
|
-
volume: this.volume,
|
|
110
|
-
prevVolume: this.prevVolume,
|
|
111
|
-
})
|
|
112
|
-
// @ts-ignore
|
|
113
|
-
this.roll.on('volume', this.changeVolume.bind(this))
|
|
114
|
-
// @ts-ignore
|
|
115
|
-
this.roll.on('advertisement_started', this.onAdStarted.bind(this))
|
|
116
|
-
// @ts-ignore
|
|
117
|
-
this.roll.on('advertisement_played', this.onAdPlayed.bind(this))
|
|
118
|
-
// @ts-ignore
|
|
119
|
-
this.roll.on('continue_ad', this._cleverContinueAd.bind(this))
|
|
120
|
-
// @ts-ignore
|
|
121
|
-
this.roll.on('advertisement_finish', this._playVideoContent.bind(this))
|
|
122
|
-
|
|
123
|
-
this.roll._requestAd({ xml, url, extension })
|
|
124
|
-
} catch (error) {
|
|
125
|
-
// LogManager.exception(error);
|
|
126
|
-
reportError(error)
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
playerResize(_: { width: number; height: number }) {
|
|
131
|
-
if (this.roll) {
|
|
132
|
-
this.roll.playerResize()
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
private onAdStarted(_: { url: string }) {
|
|
137
|
-
this.removeContainer()
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
onAdPlayed() {
|
|
141
|
-
this.isPlaying = true
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
private removeContainer() {
|
|
145
|
-
this.trigger('advertisement_started')
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
private changeVolume(obj: { volume: number; mute: boolean }) {
|
|
149
|
-
this.trigger('volume', obj)
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
// private _createAdDisplayContainer() {
|
|
153
|
-
// this._createImaContainer();
|
|
154
|
-
// assert('google' in window, 'google not found');
|
|
155
|
-
// this._adDisplayContainer = new (window.google as any).ima.AdDisplayContainer(this._imaContainer, this._contentElement);
|
|
156
|
-
// }
|
|
157
|
-
|
|
158
|
-
_createImaContainer() {
|
|
159
|
-
this._destroyImaContainer()
|
|
160
|
-
// IMA does not clean ad container when finished
|
|
161
|
-
// For the sake of simplicity, wrap into a <div> element
|
|
162
|
-
if (this._adContainer) {
|
|
163
|
-
this._imaContainer = document.createElement('div')
|
|
164
|
-
this._adContainer.appendChild(this._imaContainer)
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
_destroyImaContainer() {
|
|
169
|
-
if (this._imaContainer && this._adContainer) {
|
|
170
|
-
this._adContainer.removeChild(this._imaContainer)
|
|
171
|
-
this._imaContainer = null
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
async setupRoll() {
|
|
176
|
-
// TODO: check if this is correct
|
|
177
|
-
const dataAd = this.vastAdsOptions[this.type] || { data: [] }
|
|
178
|
-
const { oneByOne = false } = dataAd
|
|
179
|
-
let rollList = dataAd.data
|
|
180
|
-
|
|
181
|
-
if (this.type === 'middleroll') {
|
|
182
|
-
const currentStartTime = dataAd.data[this.countRoll].startTimePercent
|
|
183
|
-
|
|
184
|
-
rollList = dataAd.data.filter((el) => {
|
|
185
|
-
if (el.startTimePercent === currentStartTime) {
|
|
186
|
-
return true
|
|
187
|
-
}
|
|
188
|
-
})
|
|
189
|
-
}
|
|
190
|
-
if (this.type === 'repeatableroll') {
|
|
191
|
-
const currentStartTime = dataAd.data[this.countRoll].startTime
|
|
192
|
-
|
|
193
|
-
rollList = dataAd.data.filter((el) => {
|
|
194
|
-
if (el.startTime === currentStartTime) {
|
|
195
|
-
return true
|
|
196
|
-
}
|
|
197
|
-
})
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
if (this.type === 'middleroll' || this.type === 'repeatableroll') {
|
|
201
|
-
this.trigger('change_counter', {
|
|
202
|
-
type: this.type,
|
|
203
|
-
value: this.countRoll + rollList.length,
|
|
204
|
-
})
|
|
205
|
-
}
|
|
206
|
-
await this.startAd(this.type, { data: rollList, oneByOne })
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
async startAd(type: AdRollType, roll: AdRollDesc) {
|
|
210
|
-
// TODO
|
|
211
|
-
// Player.player.trigger('advertisementWasStarted');
|
|
212
|
-
this.core.trigger('core:advertisement:start')
|
|
213
|
-
this.container.trigger('container:advertisement:start')
|
|
214
|
-
;(this.container as any).advertisement = { type: type }
|
|
215
|
-
if (type !== 'middleroll' && type !== 'repeatableroll') {
|
|
216
|
-
console.warn('disableControls')
|
|
217
|
-
setTimeout(() => this._disableControls(), 0)
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
if (!this.adTemplates && roll) {
|
|
221
|
-
this.adTemplates = this.parseAdUrl(roll.data)
|
|
222
|
-
if (!this.adTemplates) {
|
|
223
|
-
this.trigger('disable_plugin', { type: this.type })
|
|
224
|
-
|
|
225
|
-
return
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
if (type === 'preroll') {
|
|
229
|
-
if (Browser.isMobile) {
|
|
230
|
-
this._playback.consent(() => {})
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
//чтобы реклама шла одна за другой
|
|
234
|
-
this._allURLRequest = !!roll.oneByOne
|
|
235
|
-
try {
|
|
236
|
-
const customPosterPlugin = this.container.getPlugin('poster')
|
|
237
|
-
|
|
238
|
-
customPosterPlugin.hidePlayButton()
|
|
239
|
-
} catch (error) {
|
|
240
|
-
// LogManager.exception(error);
|
|
241
|
-
reportError(error)
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
if (!this.adTemplates?.length) {
|
|
245
|
-
this.trigger('advertisement_dont_play', { type: this.type })
|
|
246
|
-
|
|
247
|
-
return
|
|
248
|
-
}
|
|
249
|
-
Log.debug('Advertisement', 'advertisement will start')
|
|
250
|
-
try {
|
|
251
|
-
const adTemplate = this.adTemplates.shift()
|
|
252
|
-
// @ts-ignore
|
|
253
|
-
await this.loadAd(adTemplate.url)
|
|
254
|
-
} catch (error) {
|
|
255
|
-
// LogManager.exception(error);
|
|
256
|
-
reportError(error)
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
_disableControls() {
|
|
261
|
-
this.container.disableMediaControl()
|
|
262
|
-
this._clickToPausePlugin?.disable()
|
|
263
|
-
// @ts-ignore
|
|
264
|
-
this._posterPlugin?.$playWrapper.hide()
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
private parseAdUrl(arr: any): AdRollItem[] | null {
|
|
268
|
-
if (!Array.isArray(arr)) {
|
|
269
|
-
return null
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
return arr.filter((el) => el.url)
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
paramsUrl(url: string): string {
|
|
276
|
-
try {
|
|
277
|
-
url = url.replace(/\{width\}/g, this.container.$el.width())
|
|
278
|
-
url = url.replace(/\{height\}/g, this.container.$el.height())
|
|
279
|
-
url = url.replace(/\{pr\}/g, String(this._pr))
|
|
280
|
-
url = url.replace(
|
|
281
|
-
/\{random\}/g,
|
|
282
|
-
String(Math.floor(Math.random() * 1000000)),
|
|
283
|
-
)
|
|
284
|
-
url = url.replace(/\{session_id\}/g, Utils.uniqueId(''))
|
|
285
|
-
url = url.replace(/\{start_delay\}/g, '0')
|
|
286
|
-
|
|
287
|
-
if (this.options.referer) {
|
|
288
|
-
url = url.replace(
|
|
289
|
-
new RegExp(/\{referer\}/g, 'g'),
|
|
290
|
-
String(this.options.referer ?? ''),
|
|
291
|
-
)
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
let playback = 1
|
|
295
|
-
|
|
296
|
-
if (this.options.autoPlay && this.options.mute) {
|
|
297
|
-
playback = 2
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
if (!this.options.autoPlay) {
|
|
301
|
-
playback = 3
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
url = url.replace(/\{playback\}/g, String(playback))
|
|
305
|
-
} catch (error) {
|
|
306
|
-
// LogManager.exception(error);
|
|
307
|
-
reportError(error)
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
return url
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
async loadAd(url: string) {
|
|
314
|
-
if (!url) {
|
|
315
|
-
return
|
|
316
|
-
}
|
|
317
|
-
try {
|
|
318
|
-
if (
|
|
319
|
-
!['middleroll', 'repeatableroll'].includes(
|
|
320
|
-
(this.container as any).advertisement.type,
|
|
321
|
-
)
|
|
322
|
-
) {
|
|
323
|
-
const spinnerPlugin = this.container.getPlugin('spinner')
|
|
324
|
-
|
|
325
|
-
spinnerPlugin?.show()
|
|
326
|
-
}
|
|
327
|
-
} catch (error) {
|
|
328
|
-
// LogManager.exception(error);
|
|
329
|
-
reportError(error)
|
|
330
|
-
}
|
|
331
|
-
url = this.paramsUrl(url)
|
|
332
|
-
|
|
333
|
-
Roll._adContainer = this._adContainer
|
|
334
|
-
Roll._contentElement = this._contentElement
|
|
335
|
-
Roll.createAdDisplayContainer()
|
|
336
|
-
this.loadXML = new LoaderXML(url)
|
|
337
|
-
let data: ExtensionData
|
|
338
|
-
|
|
339
|
-
try {
|
|
340
|
-
data = await this.loadXML.startLoad()
|
|
341
|
-
} catch (error) {
|
|
342
|
-
// LogManager.exception(error);
|
|
343
|
-
reportError(error)
|
|
344
|
-
if (this.adTemplates && this.adTemplates.length > 0) {
|
|
345
|
-
const adTemplate = this.adTemplates.shift()
|
|
346
|
-
// @ts-ignore
|
|
347
|
-
await this.loadAd(adTemplate.url)
|
|
348
|
-
} else {
|
|
349
|
-
const spinnerPlugin = this.container.getPlugin('spinner')
|
|
350
|
-
|
|
351
|
-
spinnerPlugin?.hide()
|
|
352
|
-
this.trigger('advertisement_dont_play', { type: this.type })
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
return
|
|
356
|
-
}
|
|
357
|
-
try {
|
|
358
|
-
this.firstRemaininTime = 0
|
|
359
|
-
this.$muteIcon.hide()
|
|
360
|
-
this.$skipAd.hide()
|
|
361
|
-
|
|
362
|
-
// this.volume = this._playback.volume;
|
|
363
|
-
assert(this._playback instanceof HTML5Video)
|
|
364
|
-
this.volume = (this._playback.el as HTMLMediaElement).volume
|
|
365
|
-
} catch (error) {
|
|
366
|
-
// LogManager.exception(error);
|
|
367
|
-
reportError(error)
|
|
368
|
-
}
|
|
369
|
-
this.extension = data
|
|
370
|
-
this.initializeRoll({
|
|
371
|
-
xml: data.config,
|
|
372
|
-
url: String(data.url || url),
|
|
373
|
-
extension: data,
|
|
374
|
-
})
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
_onAdError(adErrorEvent: any) {
|
|
378
|
-
try {
|
|
379
|
-
const googleError = adErrorEvent.getError()
|
|
380
|
-
const error = new Error(
|
|
381
|
-
googleError.getMessage() + ' ' + googleError.getErrorCode(),
|
|
382
|
-
)
|
|
383
|
-
|
|
384
|
-
error.name = googleError.getType()
|
|
385
|
-
// LogManager.exception(error);
|
|
386
|
-
reportError(error)
|
|
387
|
-
} catch (error) {
|
|
388
|
-
// LogManager.exception(error);
|
|
389
|
-
reportError(error)
|
|
390
|
-
}
|
|
391
|
-
Log.debug('Advertisement', 'advertisement error')
|
|
392
|
-
|
|
393
|
-
this._cleverContinueAd(true)
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
_imaEvent(eventName: string, e: any) {
|
|
397
|
-
$.isFunction((this._events as any)[eventName]) &&
|
|
398
|
-
(this._events as any)[eventName](e)
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
/**
|
|
402
|
-
* определяет, что дальше будет запускаться реклама или контент
|
|
403
|
-
*
|
|
404
|
-
*/
|
|
405
|
-
async _cleverContinueAd(data: any) {
|
|
406
|
-
this.destroyRoll()
|
|
407
|
-
const error = data.error
|
|
408
|
-
|
|
409
|
-
if (
|
|
410
|
-
(this._allURLRequest || error) &&
|
|
411
|
-
this.adTemplates &&
|
|
412
|
-
this.adTemplates.length > 0
|
|
413
|
-
) {
|
|
414
|
-
const adTemplate = this.adTemplates.shift()
|
|
415
|
-
// @ts-ignore
|
|
416
|
-
await this.loadAd(adTemplate.url)
|
|
417
|
-
|
|
418
|
-
return
|
|
419
|
-
}
|
|
420
|
-
this._playVideoContent()
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
_playVideoContent() {
|
|
424
|
-
this.destroyRoll()
|
|
425
|
-
Roll.destroyImaContainer()
|
|
426
|
-
|
|
427
|
-
const spinnerPlugin = this.container.getPlugin('spinner')
|
|
428
|
-
|
|
429
|
-
spinnerPlugin?.hide()
|
|
430
|
-
|
|
431
|
-
if (this.isPlaying) {
|
|
432
|
-
this.trigger('advertisement_finish', { type: this.type })
|
|
433
|
-
} else {
|
|
434
|
-
this.trigger('advertisement_dont_play', { type: this.type })
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
destroyRoll() {
|
|
439
|
-
if (!this.roll) {
|
|
440
|
-
return
|
|
441
|
-
}
|
|
442
|
-
// @ts-ignore
|
|
443
|
-
this.roll.off()
|
|
444
|
-
this.roll.destroy()
|
|
445
|
-
this.roll = null
|
|
446
|
-
}
|
|
447
|
-
}
|
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
import { Events, Playback } from '@clappr/core'
|
|
2
|
-
import { Events as HlsEvents, FragChangedData } from 'hls.js'
|
|
3
|
-
|
|
4
|
-
const OUT = 'out',
|
|
5
|
-
IN = 'in',
|
|
6
|
-
OUT_CONT = 'out_cont'
|
|
7
|
-
|
|
8
|
-
type CueResult = { kind?: 'in' | 'out' | 'out_cont'; duration?: number }
|
|
9
|
-
|
|
10
|
-
export default class SCTEManager extends Events {
|
|
11
|
-
private _playback: Playback | null = null
|
|
12
|
-
|
|
13
|
-
private _scteIsStarted = false
|
|
14
|
-
|
|
15
|
-
set playback(value: Playback) {
|
|
16
|
-
if (this._playback) {
|
|
17
|
-
//удалить все подписанные евенты
|
|
18
|
-
// @ts-ignore
|
|
19
|
-
if (this._playback._hls) {
|
|
20
|
-
// @ts-ignore
|
|
21
|
-
this._playback._hls.off(
|
|
22
|
-
HlsEvents.FRAG_CHANGED,
|
|
23
|
-
this._onHlsFragChanged.bind(this),
|
|
24
|
-
)
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
this._playback.off(
|
|
28
|
-
Events.PLAYBACK_PLAY_INTENT,
|
|
29
|
-
this._subscribedHlsEvents,
|
|
30
|
-
this,
|
|
31
|
-
)
|
|
32
|
-
}
|
|
33
|
-
this._playback = value
|
|
34
|
-
// @ts-ignore
|
|
35
|
-
if (!this._playback._hls) {
|
|
36
|
-
this._playback.once(
|
|
37
|
-
Events.PLAYBACK_PLAY_INTENT,
|
|
38
|
-
this._subscribedHlsEvents,
|
|
39
|
-
this,
|
|
40
|
-
)
|
|
41
|
-
} else {
|
|
42
|
-
this._subscribedHlsEvents()
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
get playback(): Playback | null {
|
|
47
|
-
return this._playback
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
_subscribedHlsEvents() {
|
|
51
|
-
// @ts-ignore
|
|
52
|
-
if (this._playback._hls) {
|
|
53
|
-
// @ts-ignore
|
|
54
|
-
this._playback._hls.off(
|
|
55
|
-
HlsEvents.FRAG_CHANGED,
|
|
56
|
-
this._onHlsFragChanged.bind(this),
|
|
57
|
-
)
|
|
58
|
-
// @ts-ignore
|
|
59
|
-
this._playback._hls.on(
|
|
60
|
-
HlsEvents.FRAG_CHANGED,
|
|
61
|
-
this._onHlsFragChanged.bind(this),
|
|
62
|
-
)
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
_onHlsFragChanged(_: HlsEvents.FRAG_CHANGED, data: FragChangedData) {
|
|
67
|
-
const { tagList } = data.frag
|
|
68
|
-
|
|
69
|
-
if (tagList) {
|
|
70
|
-
const cue = this._getCue(tagList)
|
|
71
|
-
|
|
72
|
-
if (Object.keys(cue).length > 0) {
|
|
73
|
-
if (!this._scteIsStarted) {
|
|
74
|
-
if (cue.kind === OUT || cue.kind === OUT_CONT) {
|
|
75
|
-
this._scteIsStarted = true
|
|
76
|
-
console.warn('scteroll will be started')
|
|
77
|
-
this.trigger('startSCTERoll', {
|
|
78
|
-
duration: cue.duration,
|
|
79
|
-
})
|
|
80
|
-
}
|
|
81
|
-
} else {
|
|
82
|
-
if (cue.kind === IN) {
|
|
83
|
-
console.warn('scteroll will be stopped')
|
|
84
|
-
this._stopScte()
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
} else {
|
|
88
|
-
this._stopScte()
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
_stopScte() {
|
|
94
|
-
if (this._scteIsStarted) {
|
|
95
|
-
this.trigger('stopSCTERoll')
|
|
96
|
-
this._scteIsStarted = false
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
_getCue(tagList: string[][]): CueResult {
|
|
101
|
-
let cueResult: CueResult = {
|
|
102
|
-
kind: undefined,
|
|
103
|
-
duration: undefined,
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
for (let i = 0; i < tagList.length; i++) {
|
|
107
|
-
const infoSegment = tagList[i]
|
|
108
|
-
let kind: 'in' | 'out' | 'out_cont' | undefined
|
|
109
|
-
let duration: number | undefined
|
|
110
|
-
|
|
111
|
-
infoSegment.forEach((info) => {
|
|
112
|
-
if (kind) {
|
|
113
|
-
if (kind === OUT) {
|
|
114
|
-
const dur = parseInt(info)
|
|
115
|
-
|
|
116
|
-
!isNaN(dur) && (duration = dur)
|
|
117
|
-
}
|
|
118
|
-
if (kind === OUT_CONT) {
|
|
119
|
-
const durString = info.match(/Duration=\d+/g)
|
|
120
|
-
|
|
121
|
-
if (durString) {
|
|
122
|
-
const durNumb = durString[0].match(/\d+/g)
|
|
123
|
-
|
|
124
|
-
if (durNumb) {
|
|
125
|
-
duration = parseInt(durNumb[0])
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
} else {
|
|
130
|
-
switch (info) {
|
|
131
|
-
case 'EXT-X-CUE-OUT':
|
|
132
|
-
kind = OUT
|
|
133
|
-
break
|
|
134
|
-
case 'EXT-X-CUE-OUT-CONT':
|
|
135
|
-
kind = OUT_CONT
|
|
136
|
-
break
|
|
137
|
-
case 'EXT-X-CUE-IN':
|
|
138
|
-
kind = IN
|
|
139
|
-
break
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
})
|
|
143
|
-
kind &&
|
|
144
|
-
(cueResult = {
|
|
145
|
-
kind,
|
|
146
|
-
duration,
|
|
147
|
-
})
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
return cueResult
|
|
151
|
-
}
|
|
152
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
export type AdRollType =
|
|
2
|
-
| 'preroll'
|
|
3
|
-
| 'middleroll'
|
|
4
|
-
| 'repeatableroll'
|
|
5
|
-
| 'pauseroll'
|
|
6
|
-
| 'postroll'
|
|
7
|
-
| 'scteroll'
|
|
8
|
-
|
|
9
|
-
export type AdRollItem = {
|
|
10
|
-
startTime: number
|
|
11
|
-
startTimePercent: number
|
|
12
|
-
tag: string
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export type AdRollDesc = {
|
|
16
|
-
data: AdRollItem[]
|
|
17
|
-
oneByOne?: boolean
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export type VastAdsOptions = Partial<Record<AdRollType, AdRollDesc>>
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import assert from 'assert'
|
|
2
|
-
import XHRURLHandler from './xmlhttprequest.js'
|
|
3
|
-
|
|
4
|
-
// eslint-disable-next-line max-len
|
|
5
|
-
const ERROR_MESSAGE =
|
|
6
|
-
'Current context is not supported by any of the default URLHandlers. Please provide a custom URLHandler'
|
|
7
|
-
|
|
8
|
-
export default class URLHandler {
|
|
9
|
-
static get(
|
|
10
|
-
url: string,
|
|
11
|
-
options: any,
|
|
12
|
-
cb?: (err: any | null, response?: any) => void,
|
|
13
|
-
) {
|
|
14
|
-
// Allow skip of the options param
|
|
15
|
-
if (!cb) {
|
|
16
|
-
if (typeof options === 'function') {
|
|
17
|
-
cb = options
|
|
18
|
-
}
|
|
19
|
-
options = {}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
assert(cb, 'URLHandler.get: callback is required')
|
|
23
|
-
if (options.response) {
|
|
24
|
-
// Trick: the VAST response XML document is passed as an option
|
|
25
|
-
const { response } = options
|
|
26
|
-
|
|
27
|
-
delete options.response
|
|
28
|
-
|
|
29
|
-
return cb(null, response)
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
if (options.urlhandler?.supported()) {
|
|
33
|
-
// explicitly supply your own URLHandler object
|
|
34
|
-
return options.urlhandler.get(url, options, cb)
|
|
35
|
-
}
|
|
36
|
-
if (XHRURLHandler.supported()) {
|
|
37
|
-
return XHRURLHandler.get(url, options, cb)
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
return cb(new Error(ERROR_MESSAGE))
|
|
41
|
-
}
|
|
42
|
-
}
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import { reportError } from '@gcorevideo/utils'
|
|
2
|
-
import assert from 'assert'
|
|
3
|
-
|
|
4
|
-
export default class XHRURLHandler {
|
|
5
|
-
static xhrCreate(): XMLHttpRequest | false {
|
|
6
|
-
const xhr = new window.XMLHttpRequest()
|
|
7
|
-
|
|
8
|
-
if ('withCredentials' in xhr) {
|
|
9
|
-
// check CORS support
|
|
10
|
-
return xhr
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
return false
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
static supported() {
|
|
17
|
-
return !!this.xhrCreate()
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
static get(
|
|
21
|
-
url: string,
|
|
22
|
-
options: any,
|
|
23
|
-
cb: (err: Error | null, response?: any) => void,
|
|
24
|
-
) {
|
|
25
|
-
try {
|
|
26
|
-
const xhr = this.xhrCreate()
|
|
27
|
-
assert(xhr, 'XHRURLHandler: XMLHttpRequest is not supported')
|
|
28
|
-
|
|
29
|
-
xhr.open('GET', url)
|
|
30
|
-
xhr.timeout = options.timeout || 0
|
|
31
|
-
xhr.withCredentials = options.withCredentials || false
|
|
32
|
-
xhr.onreadystatechange = function () {
|
|
33
|
-
if (xhr.readyState === 4) {
|
|
34
|
-
if (xhr.status === 200) {
|
|
35
|
-
return cb(null, xhr.response)
|
|
36
|
-
} else {
|
|
37
|
-
return cb(new Error(`XHRURLHandler: ${xhr.statusText}`))
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
return xhr.send()
|
|
43
|
-
} catch (error) {
|
|
44
|
-
// LogManager.exception(error);
|
|
45
|
-
reportError(error)
|
|
46
|
-
return cb(new Error('XHRURLHandler: Unexpected error'))
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
}
|