react-native-theoplayer 3.1.0 → 3.2.1

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 (54) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/android/src/main/java/com/theoplayer/PlayerConfigAdapter.kt +4 -0
  3. package/android/src/main/java/com/theoplayer/PlayerEventEmitter.kt +7 -2
  4. package/android/src/main/java/com/theoplayer/player/PlayerModule.kt +8 -0
  5. package/android/src/main/java/com/theoplayer/track/TrackListAdapter.kt +47 -2
  6. package/android/src/main/java/com/theoplayer/util/ViewResolver.kt +2 -2
  7. package/ios/THEOplayerRCTTextTrackEventHandler.swift +21 -17
  8. package/ios/THEOplayerRCTTrackMetadataAggregator.swift +64 -8
  9. package/ios/THEOplayerRCTView.swift +4 -0
  10. package/lib/commonjs/api/config/PlayerConfiguration.js.map +1 -1
  11. package/lib/commonjs/api/track/DateRangeCue.js +19 -0
  12. package/lib/commonjs/api/track/DateRangeCue.js.map +1 -0
  13. package/lib/commonjs/api/track/TextTrack.js +2 -0
  14. package/lib/commonjs/api/track/TextTrack.js.map +1 -1
  15. package/lib/commonjs/api/track/barrel.js +11 -0
  16. package/lib/commonjs/api/track/barrel.js.map +1 -1
  17. package/lib/commonjs/internal/THEOplayerView.js +17 -2
  18. package/lib/commonjs/internal/THEOplayerView.js.map +1 -1
  19. package/lib/commonjs/internal/adapter/THEOplayerAdapter.js +3 -3
  20. package/lib/commonjs/internal/adapter/THEOplayerAdapter.js.map +1 -1
  21. package/lib/commonjs/internal/adapter/WebEventForwarder.js +3 -0
  22. package/lib/commonjs/internal/adapter/WebEventForwarder.js.map +1 -1
  23. package/lib/commonjs/internal/adapter/web/TrackUtils.js +17 -1
  24. package/lib/commonjs/internal/adapter/web/TrackUtils.js.map +1 -1
  25. package/lib/module/api/config/PlayerConfiguration.js.map +1 -1
  26. package/lib/module/api/track/DateRangeCue.js +13 -0
  27. package/lib/module/api/track/DateRangeCue.js.map +1 -0
  28. package/lib/module/api/track/TextTrack.js +2 -0
  29. package/lib/module/api/track/TextTrack.js.map +1 -1
  30. package/lib/module/api/track/barrel.js +1 -0
  31. package/lib/module/api/track/barrel.js.map +1 -1
  32. package/lib/module/internal/THEOplayerView.js +18 -2
  33. package/lib/module/internal/THEOplayerView.js.map +1 -1
  34. package/lib/module/internal/adapter/THEOplayerAdapter.js +3 -3
  35. package/lib/module/internal/adapter/THEOplayerAdapter.js.map +1 -1
  36. package/lib/module/internal/adapter/WebEventForwarder.js +4 -1
  37. package/lib/module/internal/adapter/WebEventForwarder.js.map +1 -1
  38. package/lib/module/internal/adapter/web/TrackUtils.js +16 -1
  39. package/lib/module/internal/adapter/web/TrackUtils.js.map +1 -1
  40. package/lib/typescript/api/config/PlayerConfiguration.d.ts +4 -0
  41. package/lib/typescript/api/track/DateRangeCue.d.ts +61 -0
  42. package/lib/typescript/api/track/TextTrack.d.ts +4 -1
  43. package/lib/typescript/api/track/barrel.d.ts +1 -0
  44. package/lib/typescript/internal/THEOplayerView.d.ts +2 -1
  45. package/lib/typescript/internal/adapter/web/TrackUtils.d.ts +2 -1
  46. package/package.json +1 -1
  47. package/src/api/config/PlayerConfiguration.ts +5 -0
  48. package/src/api/track/DateRangeCue.ts +74 -0
  49. package/src/api/track/TextTrack.ts +3 -0
  50. package/src/api/track/barrel.ts +1 -0
  51. package/src/internal/THEOplayerView.tsx +19 -3
  52. package/src/internal/adapter/THEOplayerAdapter.ts +3 -3
  53. package/src/internal/adapter/WebEventForwarder.ts +5 -0
  54. package/src/internal/adapter/web/TrackUtils.ts +18 -1
package/CHANGELOG.md CHANGED
@@ -5,6 +5,22 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.1.0/)
6
6
  and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [3.2.1] - 23-12-07
9
+
10
+ ### Fixed
11
+
12
+ - Fixed an issue on Android where `EnterCue` and `ExitCue` text track events did not contain the `trackUid` property.
13
+
14
+ ## [3.2.0] - 23-11-29
15
+
16
+ ### Fixed
17
+
18
+ - Fixed an issue on iOS and Android were selecting an audio, video or text track that has a `uid` with value `0`, would fail.
19
+
20
+ ### Added
21
+
22
+ - Added support for HLS #EXT-X-DATERANGE timed metadata tags. The tags appear as cues in a dedicated text track with type `daterange`.
23
+
8
24
  ## [3.1.0] - 23-10-27
9
25
 
10
26
  ### Changed
@@ -18,6 +18,7 @@ private const val PROP_PRELOAD = "preload"
18
18
  private const val PROP_UI_ENABLED = "uiEnabled"
19
19
  private const val PROP_CAST_STRATEGY = "strategy"
20
20
  private const val PROP_RETRY_CONFIG = "retryConfiguration"
21
+ private const val PROP_HLS_DATE_RANGE = "hlsDateRange"
21
22
  private const val PROP_RETRY_MAX_RETRIES = "maxRetries"
22
23
  private const val PROP_RETRY_MIN_BACKOFF = "minimumBackoff"
23
24
  private const val PROP_RETRY_MAX_BACKOFF = "maximumBackoff"
@@ -44,6 +45,9 @@ class PlayerConfigAdapter(private val configProps: ReadableMap?) {
44
45
  if (hasKey(PROP_RETRY_CONFIG)) {
45
46
  networkConfiguration(networkConfig())
46
47
  }
48
+ if (hasKey(PROP_HLS_DATE_RANGE)) {
49
+ hlsDateRange(getBoolean(PROP_HLS_DATE_RANGE))
50
+ }
47
51
  pipConfiguration(PipConfiguration.Builder().build())
48
52
  }
49
53
  }.build()
@@ -38,6 +38,7 @@ import com.theoplayer.android.api.player.track.mediatrack.quality.AudioQuality
38
38
  import com.theoplayer.android.api.player.track.mediatrack.quality.Quality
39
39
  import com.theoplayer.android.api.player.track.mediatrack.quality.VideoQuality
40
40
  import com.theoplayer.android.api.player.track.texttrack.TextTrack
41
+ import com.theoplayer.android.api.player.track.texttrack.TextTrackKind
41
42
  import com.theoplayer.android.api.player.track.texttrack.TextTrackMode
42
43
  import com.theoplayer.cast.CastEventAdapter
43
44
  import com.theoplayer.presentation.PresentationModeChangeContext
@@ -436,14 +437,14 @@ class PlayerEventEmitter internal constructor(
436
437
  }
437
438
 
438
439
  private val onTextTrackEnterCue = EventListener<EnterCueEvent> { event ->
439
- val payload = PayloadBuilder().textTrackCue(event.cue, null /*TODO*/).build().apply {
440
+ val payload = PayloadBuilder().textTrackCue(event.cue, event.track).build().apply {
440
441
  putInt(EVENT_PROP_TYPE, TextTrackCueEventType.ENTER_CUE.type)
441
442
  }
442
443
  receiveEvent(EVENT_TEXTTRACK_EVENT, payload)
443
444
  }
444
445
 
445
446
  private val onTextTrackExitCue = EventListener<ExitCueEvent> { event ->
446
- val payload = PayloadBuilder().textTrackCue(event.cue, null /*TODO*/).build().apply {
447
+ val payload = PayloadBuilder().textTrackCue(event.cue, event.track).build().apply {
447
448
  putInt(EVENT_PROP_TYPE, TextTrackCueEventType.EXIT_CUE.type)
448
449
  }
449
450
  receiveEvent(EVENT_TEXTTRACK_EVENT, payload)
@@ -474,6 +475,10 @@ class PlayerEventEmitter internal constructor(
474
475
  }
475
476
 
476
477
  private fun onTextTrackAdd(event: AddTrackEvent) {
478
+ // By default, set metadata tracks to mode 'hidden', until we add an API to set the mode.
479
+ if (event.track.kind == TextTrackKind.METADATA.type) {
480
+ event.track.mode = TextTrackMode.HIDDEN
481
+ }
477
482
  dispatchTextTrackEvent(TrackEventType.ADD_TRACK, event.track)
478
483
  }
479
484
 
@@ -98,6 +98,10 @@ class PlayerModule(context: ReactApplicationContext) : ReactContextBaseJavaModul
98
98
 
99
99
  @ReactMethod
100
100
  fun setSelectedAudioTrack(tag: Int, uid: Int) {
101
+ if (uid == -1) {
102
+ // Do not allow disabling all audio tracks
103
+ return
104
+ }
101
105
  viewResolver.resolveViewByTag(tag) { view: ReactTHEOplayerView? ->
102
106
  view?.player?.let {
103
107
  for (track in it.audioTracks) {
@@ -109,6 +113,10 @@ class PlayerModule(context: ReactApplicationContext) : ReactContextBaseJavaModul
109
113
 
110
114
  @ReactMethod
111
115
  fun setSelectedVideoTrack(tag: Int, uid: Int) {
116
+ if (uid == -1) {
117
+ // Do not allow disabling all video tracks
118
+ return
119
+ }
112
120
  viewResolver.resolveViewByTag(tag) { view: ReactTHEOplayerView? ->
113
121
  view?.player?.let {
114
122
  for (track in it.videoTracks) {
@@ -11,6 +11,7 @@ import com.theoplayer.android.api.player.track.mediatrack.quality.Quality
11
11
  import com.theoplayer.android.api.player.track.mediatrack.quality.AudioQuality
12
12
  import com.theoplayer.android.api.player.track.mediatrack.quality.VideoQuality
13
13
  import com.theoplayer.android.api.player.track.mediatrack.MediaTrackList
14
+ import com.theoplayer.android.api.player.track.texttrack.cue.DateRangeCue
14
15
  import com.theoplayer.util.TypeUtils
15
16
 
16
17
  private const val PROP_ID = "id"
@@ -35,6 +36,16 @@ private const val PROP_STARTTIME = "startTime"
35
36
  private const val PROP_ENDTIME = "endTime"
36
37
  private const val PROP_CUES = "cues"
37
38
  private const val PROP_CUE_CONTENT = "content"
39
+ private const val PROP_ATTRIBUTE_CLASS = "class"
40
+ private const val PROP_STARTDATE = "startDate"
41
+ private const val PROP_ENDDATE = "endDate"
42
+ private const val PROP_DURATION = "duration"
43
+ private const val PROP_PLANNED_DURATION = "plannedDuration"
44
+ private const val PROP_END_ON_NEXT = "endOnNext"
45
+ private const val PROP_SCTE35CMD = "scte35Cmd"
46
+ private const val PROP_SCTE35OUT = "scte35Out"
47
+ private const val PROP_SCTE35IN = "scte35In"
48
+ private const val PROP_CUSTOM_ATTRIBUTES = "customAttributes"
38
49
 
39
50
  object TrackListAdapter {
40
51
 
@@ -85,6 +96,38 @@ object TrackListAdapter {
85
96
  content.optString("content") ?: content.optString("contentString")
86
97
  )
87
98
  }
99
+
100
+ if (cue is DateRangeCue) {
101
+ cue.attributeClass?.run {
102
+ cuePayload.putString(PROP_ATTRIBUTE_CLASS, this)
103
+ }
104
+ cuePayload.putDouble(PROP_STARTDATE, cue.startDate.time.toDouble())
105
+ cue.endDate?.run {
106
+ cuePayload.putDouble(PROP_ENDDATE, this.time.toDouble())
107
+ }
108
+ cue.duration?.run {
109
+ cuePayload.putDouble(PROP_DURATION, TypeUtils.encodeInfNan(1e3 * this))
110
+ }
111
+ cue.plannedDuration?.run {
112
+ cuePayload.putDouble(PROP_PLANNED_DURATION, TypeUtils.encodeInfNan(1e3 * this))
113
+ }
114
+ cuePayload.putBoolean(PROP_END_ON_NEXT, cue.isEndOnNext)
115
+ cue.customAttributes?.asMap()?.run {
116
+ val attributes = Arguments.createMap()
117
+ forEach { (key, value) ->
118
+ when (value) {
119
+ is String -> attributes.putString(key, value)
120
+ is Boolean -> attributes.putBoolean(key, value)
121
+ is Int -> attributes.putInt(key, value)
122
+ is Double -> attributes.putDouble(key, value)
123
+ // TODO: support array & sub-objects
124
+ }
125
+ }
126
+ cuePayload.putMap(PROP_CUSTOM_ATTRIBUTES, attributes)
127
+ }
128
+ // TODO: Add SCTE marker properties
129
+ }
130
+
88
131
  return cuePayload
89
132
  }
90
133
 
@@ -128,7 +171,8 @@ object TrackListAdapter {
128
171
  qualityList?.forEach { quality ->
129
172
  qualities.pushMap(fromAudioQuality(quality))
130
173
  }
131
- } catch (ignore: NullPointerException) {}
174
+ } catch (ignore: NullPointerException) {
175
+ }
132
176
  audioTrackPayload.putArray(PROP_QUALITIES, qualities)
133
177
  val activeQuality = audioTrack.activeQuality
134
178
  if (activeQuality != null) {
@@ -178,7 +222,8 @@ object TrackListAdapter {
178
222
  qualities.pushMap(fromVideoQuality(quality as VideoQuality))
179
223
  }
180
224
  }
181
- } catch (ignore: java.lang.NullPointerException) {}
225
+ } catch (ignore: java.lang.NullPointerException) {
226
+ }
182
227
  videoTrackPayload.putArray(PROP_QUALITIES, qualities)
183
228
  val activeQuality = videoTrack.activeQuality
184
229
  if (activeQuality != null) {
@@ -22,9 +22,9 @@ class ViewResolver(private val reactContext: ReactApplicationContext) {
22
22
  uiManager?.addUIBlock {
23
23
  try {
24
24
  onResolved(it.resolveView(tag) as ReactTHEOplayerView)
25
- } catch (ignore: Exception) {
25
+ } catch (e: Exception) {
26
26
  // The ReactTHEOplayerView instance could not be resolved: log but do not forward exception.
27
- Log.w(TAG, "Failed to resolve ReactTHEOplayerView tag $tag")
27
+ Log.e(TAG, "Failed to resolve ReactTHEOplayerView tag $tag: $e")
28
28
  onResolved(null)
29
29
  }
30
30
  }
@@ -53,14 +53,14 @@ class THEOplayerRCTTextTrackEventHandler {
53
53
  }
54
54
 
55
55
  // ADD_TRACK
56
- self.addTrackListener = player.textTracks.addEventListener(type: TextTrackListEventTypes.ADD_TRACK) { [weak self] event in
57
- guard let welf = self else { return }
56
+ self.addTrackListener = player.textTracks.addEventListener(type: TextTrackListEventTypes.ADD_TRACK) { [weak self, weak player] event in
57
+ guard let welf = self, let wplayer = player else { return }
58
58
  if let forwardedTextTrackListEvent = welf.onNativeTextTrackListEvent,
59
59
  let textTrack = event.track as? TextTrack {
60
60
  if DEBUG_THEOPLAYER_EVENTS { PrintUtils.printLog(logText: "[NATIVE] Received ADD_TRACK event from THEOplayer textTrack list: trackUid = \(textTrack.uid)") }
61
61
  // trigger tracklist event
62
62
  forwardedTextTrackListEvent([
63
- "track" : THEOplayerRCTTrackMetadataAggregator.aggregatedTextTrackInfo(textTrack: textTrack),
63
+ "track" : THEOplayerRCTTrackMetadataAggregator.aggregatedTextTrackInfo(textTrack: textTrack, player: wplayer),
64
64
  "type" : TrackListEventType.ADD_TRACK.rawValue
65
65
  ])
66
66
  // start listening for cue events on this track and keep listener for later removal
@@ -77,14 +77,14 @@ class THEOplayerRCTTextTrackEventHandler {
77
77
  if DEBUG_EVENTHANDLER { PrintUtils.printLog(logText: "[NATIVE] AddTrack listener attached to THEOplayer textTrack list") }
78
78
 
79
79
  // REMOVE_TRACK
80
- self.removeTrackListener = player.textTracks.addEventListener(type: TextTrackListEventTypes.REMOVE_TRACK) { [weak self] event in
81
- guard let welf = self else { return }
80
+ self.removeTrackListener = player.textTracks.addEventListener(type: TextTrackListEventTypes.REMOVE_TRACK) { [weak self, weak player] event in
81
+ guard let welf = self, let wplayer = player else { return }
82
82
  if let forwardedTextTrackListEvent = welf.onNativeTextTrackListEvent,
83
83
  let textTrack = event.track as? TextTrack {
84
84
  if DEBUG_THEOPLAYER_EVENTS { PrintUtils.printLog(logText: "[NATIVE] Received REMOVE_TRACK event from THEOplayer textTrack list: trackUid = \(textTrack.uid)") }
85
85
  // trigger tracklist event
86
86
  forwardedTextTrackListEvent([
87
- "track" : THEOplayerRCTTrackMetadataAggregator.aggregatedTextTrackInfo(textTrack: textTrack),
87
+ "track" : THEOplayerRCTTrackMetadataAggregator.aggregatedTextTrackInfo(textTrack: textTrack, player: wplayer),
88
88
  "type" : TrackListEventType.REMOVE_TRACK.rawValue
89
89
  ])
90
90
  // stop listening for cue events on this track
@@ -109,14 +109,14 @@ class THEOplayerRCTTextTrackEventHandler {
109
109
  if DEBUG_EVENTHANDLER { PrintUtils.printLog(logText: "[NATIVE] RemoveTrack listener attached to THEOplayer textTrack list") }
110
110
 
111
111
  // CHANGE
112
- self.changeTrackListener = player.textTracks.addEventListener(type: TextTrackListEventTypes.CHANGE) { [weak self] event in
113
- guard let welf = self else { return }
112
+ self.changeTrackListener = player.textTracks.addEventListener(type: TextTrackListEventTypes.CHANGE) { [weak self, weak player] event in
113
+ guard let welf = self, let wplayer = player else { return }
114
114
  if let forwardedTextTrackListEvent = welf.onNativeTextTrackListEvent,
115
115
  let textTrack = event.track as? TextTrack {
116
116
  if DEBUG_THEOPLAYER_EVENTS { PrintUtils.printLog(logText: "[NATIVE] Received CHANGE event from THEOplayer textTrack list: trackUid = \(textTrack.uid)") }
117
117
  // trigger tracklist event
118
118
  forwardedTextTrackListEvent([
119
- "track" : THEOplayerRCTTrackMetadataAggregator.aggregatedTextTrackInfo(textTrack: textTrack),
119
+ "track" : THEOplayerRCTTrackMetadataAggregator.aggregatedTextTrackInfo(textTrack: textTrack, player: wplayer),
120
120
  "type" : TrackListEventType.CHANGE_TRACK.rawValue
121
121
  ])
122
122
  }
@@ -176,48 +176,52 @@ class THEOplayerRCTTextTrackEventHandler {
176
176
  // MARK: - dynamic textTrack Listeners
177
177
  private func addCueListener(_ event: AddCueEvent) {
178
178
  if let forwardedTextTrackEvent = self.onNativeTextTrackEvent,
179
- let textTrack = event.cue.track {
179
+ let textTrack = event.cue.track,
180
+ let player = self.player {
180
181
  if DEBUG_THEOPLAYER_EVENTS { PrintUtils.printLog(logText: "[NATIVE] Received ADD_CUE event from textTrack: trackUid = \(textTrack.uid), cueUid = \(event.cue.uid)") }
181
182
  forwardedTextTrackEvent([
182
183
  "trackUid" : textTrack.uid,
183
184
  "type": TrackCueEventType.ADD_CUE.rawValue,
184
- "cue": THEOplayerRCTTrackMetadataAggregator.aggregatedTextTrackCueInfo(textTrackCue: event.cue)
185
+ "cue": THEOplayerRCTTrackMetadataAggregator.aggregatedTextTrackCueInfo(textTrackCue: event.cue, player: player)
185
186
  ])
186
187
  }
187
188
  }
188
189
 
189
190
  private func removeCueListener(_ event: RemoveCueEvent) {
190
191
  if let forwardedTextTrackEvent = self.onNativeTextTrackEvent,
191
- let textTrack = event.cue.track {
192
+ let textTrack = event.cue.track,
193
+ let player = self.player {
192
194
  if DEBUG_THEOPLAYER_EVENTS { PrintUtils.printLog(logText: "[NATIVE] Received REMOVE_CUE event from textTrack: trackUid = \(textTrack.uid), cueUid = \(event.cue.uid)") }
193
195
  forwardedTextTrackEvent([
194
196
  "trackUid" : textTrack.uid,
195
197
  "type": TrackCueEventType.REMOVE_CUE.rawValue,
196
- "cue": THEOplayerRCTTrackMetadataAggregator.aggregatedTextTrackCueInfo(textTrackCue: event.cue)
198
+ "cue": THEOplayerRCTTrackMetadataAggregator.aggregatedTextTrackCueInfo(textTrackCue: event.cue, player: player)
197
199
  ])
198
200
  }
199
201
  }
200
202
 
201
203
  private func enterCueListener(_ event: EnterCueEvent) {
202
204
  if let forwardedTextTrackEvent = self.onNativeTextTrackEvent,
203
- let textTrack = event.cue.track {
205
+ let textTrack = event.cue.track,
206
+ let player = self.player {
204
207
  if DEBUG_THEOPLAYER_EVENTS { PrintUtils.printLog(logText: "[NATIVE] Received ENTER_CUE event from textTrack: trackUid = \(textTrack.uid), cueUid = \(event.cue.uid)") }
205
208
  forwardedTextTrackEvent([
206
209
  "trackUid" : textTrack.uid,
207
210
  "type": TrackCueEventType.ENTER_CUE.rawValue,
208
- "cue": THEOplayerRCTTrackMetadataAggregator.aggregatedTextTrackCueInfo(textTrackCue: event.cue)
211
+ "cue": THEOplayerRCTTrackMetadataAggregator.aggregatedTextTrackCueInfo(textTrackCue: event.cue, player: player)
209
212
  ])
210
213
  }
211
214
  }
212
215
 
213
216
  private func exitCueListener(_ event: ExitCueEvent) {
214
217
  if let forwardedTextTrackEvent = self.onNativeTextTrackEvent,
215
- let textTrack = event.cue.track {
218
+ let textTrack = event.cue.track,
219
+ let player = self.player {
216
220
  if DEBUG_THEOPLAYER_EVENTS { PrintUtils.printLog(logText: "[NATIVE] Received EXIT_CUE event from textTrack: trackUid = \(textTrack.uid), cueUid = \(event.cue.uid)") }
217
221
  forwardedTextTrackEvent([
218
222
  "trackUid" : textTrack.uid,
219
223
  "type": TrackCueEventType.EXIT_CUE.rawValue,
220
- "cue": THEOplayerRCTTrackMetadataAggregator.aggregatedTextTrackCueInfo(textTrackCue: event.cue)
224
+ "cue": THEOplayerRCTTrackMetadataAggregator.aggregatedTextTrackCueInfo(textTrackCue: event.cue, player: player)
221
225
  ])
222
226
  }
223
227
  }
@@ -24,7 +24,14 @@ let PROP_STARTTIME: String = "startTime"
24
24
  let PROP_ENDTIME: String = "endTime"
25
25
  let PROP_CUES: String = "cues"
26
26
  let PROP_CUE_CONTENT: String = "content"
27
+ let PROP_CUE_CUSTOM_ATTRIBUTES: String = "customAttributes"
27
28
  let PROP_SRC: String = "src"
29
+ let PROP_START_DATE: String = "startDate"
30
+ let PROP_END_DATE: String = "endDate"
31
+ let PROP_ATTRIBUTE_CLASS: String = "class"
32
+ let PROP_DURATION: String = "duration"
33
+ let PROP_PLANNED_DURATION: String = "plannedDuration"
34
+ let PROP_END_ON_NEXT: String = "endOnNext"
28
35
 
29
36
  class THEOplayerRCTTrackMetadataAggregator {
30
37
 
@@ -33,7 +40,7 @@ class THEOplayerRCTTrackMetadataAggregator {
33
40
  let audioTracks: AudioTrackList = player.audioTracks
34
41
  let videoTracks: VideoTrackList = player.videoTracks
35
42
  return [
36
- EVENT_PROP_TEXT_TRACKS : THEOplayerRCTTrackMetadataAggregator.aggregatedTextTrackListInfo(textTracks: textTracks, metadataTracks: metadataTracksInfo),
43
+ EVENT_PROP_TEXT_TRACKS : THEOplayerRCTTrackMetadataAggregator.aggregatedTextTrackListInfo(textTracks: textTracks, metadataTracks: metadataTracksInfo, player: player),
37
44
  EVENT_PROP_AUDIO_TRACKS : THEOplayerRCTTrackMetadataAggregator.aggregatedAudioTrackListInfo(audioTracks: audioTracks),
38
45
  EVENT_PROP_VIDEO_TRACKS : THEOplayerRCTTrackMetadataAggregator.aggregatedVideoTrackListInfo(videoTracks: videoTracks),
39
46
  EVENT_PROP_SELECTED_TEXT_TRACK: THEOplayerRCTTrackMetadataAggregator.selectedTextTrack(textTracks: textTracks),
@@ -44,19 +51,19 @@ class THEOplayerRCTTrackMetadataAggregator {
44
51
  }
45
52
 
46
53
  // MARK: TEXTTRACKS
47
- class func aggregatedTextTrackListInfo(textTracks: TextTrackList, metadataTracks: [[String:Any]]) -> [[String:Any]] {
54
+ class func aggregatedTextTrackListInfo(textTracks: TextTrackList, metadataTracks: [[String:Any]], player: THEOplayer) -> [[String:Any]] {
48
55
  var trackEntries:[[String:Any]] = metadataTracks
49
56
  guard textTracks.count > 0 else {
50
57
  return trackEntries
51
58
  }
52
59
  for i in 0...textTracks.count-1 {
53
60
  let textTrack: TextTrack = textTracks.get(i)
54
- trackEntries.append(THEOplayerRCTTrackMetadataAggregator.aggregatedTextTrackInfo(textTrack: textTrack))
61
+ trackEntries.append(THEOplayerRCTTrackMetadataAggregator.aggregatedTextTrackInfo(textTrack: textTrack, player: player))
55
62
  }
56
63
  return trackEntries
57
64
  }
58
65
 
59
- class func aggregatedTextTrackInfo(textTrack: TextTrack) -> [String:Any] {
66
+ class func aggregatedTextTrackInfo(textTrack: TextTrack, player: THEOplayer) -> [String:Any] {
60
67
  var entry: [String:Any] = [:]
61
68
  entry[PROP_ID] = textTrack.id
62
69
  entry[PROP_UID] = textTrack.uid
@@ -70,7 +77,7 @@ class THEOplayerRCTTrackMetadataAggregator {
70
77
  if !textTrack.cues.isEmpty {
71
78
  var cueList: [[String:Any]] = []
72
79
  for cue in textTrack.cues {
73
- cueList.append(THEOplayerRCTTrackMetadataAggregator.aggregatedTextTrackCueInfo(textTrackCue: cue))
80
+ cueList.append(THEOplayerRCTTrackMetadataAggregator.aggregatedTextTrackCueInfo(textTrackCue: cue, player: player))
74
81
  }
75
82
  entry[PROP_CUES] = cueList
76
83
  }
@@ -91,17 +98,66 @@ class THEOplayerRCTTrackMetadataAggregator {
91
98
  }
92
99
 
93
100
  // MARK: TEXTTRACK CUES
94
- class func aggregatedTextTrackCueInfo(textTrackCue: TextTrackCue) -> [String:Any] {
101
+ class func aggregatedTextTrackCueInfo(textTrackCue: TextTrackCue, player: THEOplayer) -> [String:Any] {
95
102
  var entry: [String:Any] = [:]
96
103
  entry[PROP_ID] = textTrackCue.id
97
104
  entry[PROP_UID] = textTrackCue.uid
98
- entry[PROP_STARTTIME] = THEOplayerRCTTypeUtils.encodeInfNan((textTrackCue.startTime ?? 0) * 1000)
99
- entry[PROP_ENDTIME] = THEOplayerRCTTypeUtils.encodeInfNan((textTrackCue.endTime ?? 0) * 1000)
105
+ var startTime = textTrackCue.startTime
106
+ var endTime = textTrackCue.endTime
107
+ if let dateRangeCue = textTrackCue as? DateRangeCue,
108
+ let programDateTime = player.currentProgramDateTime?.timeIntervalSince1970 {
109
+ let currentTime = player.currentTime
110
+ let offset = programDateTime - currentTime
111
+ startTime = dateRangeCue.startDate.timeIntervalSince1970 - offset
112
+ endTime = dateRangeCue.endDate != nil ? dateRangeCue.endDate!.timeIntervalSince1970 - offset : .infinity
113
+ }
114
+ entry[PROP_STARTTIME] = THEOplayerRCTTypeUtils.encodeInfNan((startTime ?? 0) * 1000)
115
+ entry[PROP_ENDTIME] = THEOplayerRCTTypeUtils.encodeInfNan((endTime ?? 0) * 1000)
100
116
  if let content = textTrackCue.content {
101
117
  entry[PROP_CUE_CONTENT] = content
102
118
  } else if let contentString = textTrackCue.contentString {
103
119
  entry[PROP_CUE_CONTENT] = contentString
104
120
  }
121
+ if let dateRangeCue = textTrackCue as? DateRangeCue {
122
+ entry[PROP_START_DATE] = dateRangeCue.startDate.timeIntervalSince1970 * 1000
123
+ if let endDate = dateRangeCue.endDate {
124
+ entry[PROP_END_DATE] = endDate.timeIntervalSince1970 * 1000
125
+ }
126
+ if let attributeClass = dateRangeCue.attributeClass {
127
+ entry[PROP_ATTRIBUTE_CLASS] = attributeClass
128
+ }
129
+ if let duration = dateRangeCue.duration {
130
+ entry[PROP_DURATION] = THEOplayerRCTTypeUtils.encodeInfNan(duration * 1000)
131
+ }
132
+ if let plannedDuration = dateRangeCue.plannedDuration {
133
+ entry[PROP_PLANNED_DURATION] = THEOplayerRCTTypeUtils.encodeInfNan(plannedDuration * 1000)
134
+ }
135
+ entry[PROP_END_ON_NEXT] = dateRangeCue.endOnNext
136
+ let customAttributes = dateRangeCue.customAttributes
137
+ let customAttributesDict = customAttributes.getAttributesAsDictionary()
138
+ if !customAttributesDict.isEmpty {
139
+ var attributesEntry: [String:Any] = [:]
140
+ for (key, _) in customAttributesDict {
141
+ do {
142
+ // try reading as string
143
+ attributesEntry[key] = try customAttributes.getString(for: key)
144
+ } catch {
145
+ do {
146
+ // try reading as double
147
+ attributesEntry[key] = try customAttributes.getDouble(for: key)
148
+ } catch {
149
+ do {
150
+ // try reading as data
151
+ attributesEntry[key] = try customAttributes.getBytes(for: key)
152
+ } catch {
153
+ print("Unable to extract customAttribute from DateRange cue. Content is limited to String, Double or Data.")
154
+ }
155
+ }
156
+ }
157
+ }
158
+ entry[PROP_CUE_CUSTOM_ATTRIBUTES] = attributesEntry
159
+ }
160
+ }
105
161
  return entry
106
162
  }
107
163
 
@@ -37,6 +37,7 @@ public class THEOplayerRCTView: UIView {
37
37
  private var license: String?
38
38
  private var licenseUrl: String?
39
39
  private var chromeless: Bool = true
40
+ private var hlsDateRange: Bool = false
40
41
  private var config: THEOplayerConfiguration?
41
42
 
42
43
  // MARK: - Initialisation / view setup
@@ -108,6 +109,7 @@ public class THEOplayerRCTView: UIView {
108
109
  pip: self.playerPipConfiguration(),
109
110
  ads: self.playerAdsConfiguration(),
110
111
  cast: self.playerCastConfiguration(),
112
+ hlsDateRange: self.hlsDateRange,
111
113
  license: self.license,
112
114
  licenseUrl: self.licenseUrl))
113
115
  self.initAdsIntegration()
@@ -120,6 +122,7 @@ public class THEOplayerRCTView: UIView {
120
122
  private func initPlayer() -> THEOplayer? {
121
123
  self.player = THEOplayer(configuration: THEOplayerConfiguration(chromeless: self.chromeless,
122
124
  ads: self.playerAdsConfiguration(),
125
+ hlsDateRange: self.hlsDateRange,
123
126
  license: self.license,
124
127
  licenseUrl: self.licenseUrl,
125
128
  pip: self.playerPipConfiguration()))
@@ -168,6 +171,7 @@ public class THEOplayerRCTView: UIView {
168
171
  self.license = configDict["license"] as? String
169
172
  self.licenseUrl = configDict["licenseUrl"] as? String
170
173
  self.chromeless = configDict["chromeless"] as? Bool ?? true
174
+ self.hlsDateRange = configDict["hlsDateRange"] as? Bool ?? false
171
175
  self.parseAdsConfig(configDict: configDict)
172
176
  self.parseCastConfig(configDict: configDict)
173
177
  if DEBUG_VIEW { PrintUtils.printLog(logText: "[NATIVE] config prop updated.") }
@@ -1 +1 @@
1
- {"version":3,"names":[],"sources":["PlayerConfiguration.ts"],"sourcesContent":["import type { AdsConfiguration } from '../ads/AdsConfiguration';\nimport type { CastConfiguration } from '../cast/CastConfiguration';\nimport type { MediaControlConfiguration } from '../media/MediaControlConfiguration';\nimport type { RetryConfiguration } from '../utils/RetryConfiguration';\n\nexport interface PlayerConfiguration {\n /**\n * The directory in which the THEOplayer library worker files are located.\n * These worker files are THEOplayer.transmux.*\n *\n * @remarks\n * <br/> - This parameter is required when using a HLS source and has no default.\n *\n * @example\n * `'/lib/theoplayer/'`\n */\n libraryLocation?: string;\n\n /**\n * The muted autoplay policy for web.\n *\n * @remarks\n * <br/> - The muted autoplay policy is impacted by this property and {@link SourceConfiguration.mutedAutoplay}.\n *\n * @defaultValue `'none'`.\n */\n mutedAutoplay?: MutedAutoplayConfiguration;\n\n /**\n * The ads configuration for the player.\n */\n ads?: AdsConfiguration;\n\n /**\n * The cast configuration for the player.\n */\n cast?: CastConfiguration;\n\n /**\n * The configuration of media controls and media sessions across platforms.\n */\n mediaControl?: MediaControlConfiguration;\n\n /**\n * The license for the player\n */\n readonly license?: string;\n\n /**\n * The url to fetch the license for the player\n */\n readonly licenseUrl?: string;\n\n /**\n * Sets whether the native player is chromeless (without UI).\n *\n * @remarks\n * <br/> - This parameter only applies to Web platforms.\n */\n readonly chromeless?: boolean;\n\n /**\n * The retry configuration for the player.\n *\n * @remarks\n * <br/> - This parameter only applies to Web and Android platforms.\n */\n readonly retryConfiguration?: RetryConfiguration;\n}\n\n/**\n * The muted autoplay policy of a player for web.\n * <br/> - `'none'`: Disallow muted autoplay. If the player is requested to autoplay while unmuted, and the platform does not support unmuted autoplay, the player will not start playback.\n * <br/> - `'all'`: Allow muted autoplay. If the player is requested to autoplay while unmuted, and the platform supports muted autoplay, the player will start muted playback.\n * <br/> - `'content'`: Allow muted autoplay only for the main content. Disallow muted autoplay for e.g. advertisements. (Not yet supported.)\n *\n * @public\n */\nexport type MutedAutoplayConfiguration = 'none' | 'all' | 'content';\n"],"mappings":""}
1
+ {"version":3,"names":[],"sources":["PlayerConfiguration.ts"],"sourcesContent":["import type { AdsConfiguration } from '../ads/AdsConfiguration';\nimport type { CastConfiguration } from '../cast/CastConfiguration';\nimport type { MediaControlConfiguration } from '../media/MediaControlConfiguration';\nimport type { RetryConfiguration } from '../utils/RetryConfiguration';\n\nexport interface PlayerConfiguration {\n /**\n * The directory in which the THEOplayer library worker files are located.\n * These worker files are THEOplayer.transmux.*\n *\n * @remarks\n * <br/> - This parameter is required when using a HLS source and has no default.\n *\n * @example\n * `'/lib/theoplayer/'`\n */\n libraryLocation?: string;\n\n /**\n * The muted autoplay policy for web.\n *\n * @remarks\n * <br/> - The muted autoplay policy is impacted by this property and {@link SourceConfiguration.mutedAutoplay}.\n *\n * @defaultValue `'none'`.\n */\n mutedAutoplay?: MutedAutoplayConfiguration;\n\n /**\n * The ads configuration for the player.\n */\n ads?: AdsConfiguration;\n\n /**\n * The cast configuration for the player.\n */\n cast?: CastConfiguration;\n\n /**\n * The configuration of media controls and media sessions across platforms.\n */\n mediaControl?: MediaControlConfiguration;\n\n /**\n * The license for the player\n */\n readonly license?: string;\n\n /**\n * The url to fetch the license for the player\n */\n readonly licenseUrl?: string;\n\n /**\n * Sets whether the native player is chromeless (without UI).\n *\n * @remarks\n * <br/> - This parameter only applies to Web platforms.\n */\n readonly chromeless?: boolean;\n\n /**\n * Sets whether DateRange tags from the playlists should be imported as a textTrack.\n */\n readonly hlsDateRange?: boolean;\n\n /**\n * The retry configuration for the player.\n *\n * @remarks\n * <br/> - This parameter only applies to Web and Android platforms.\n */\n readonly retryConfiguration?: RetryConfiguration;\n}\n\n/**\n * The muted autoplay policy of a player for web.\n * <br/> - `'none'`: Disallow muted autoplay. If the player is requested to autoplay while unmuted, and the platform does not support unmuted autoplay, the player will not start playback.\n * <br/> - `'all'`: Allow muted autoplay. If the player is requested to autoplay while unmuted, and the platform supports muted autoplay, the player will start muted playback.\n * <br/> - `'content'`: Allow muted autoplay only for the main content. Disallow muted autoplay for e.g. advertisements. (Not yet supported.)\n *\n * @public\n */\nexport type MutedAutoplayConfiguration = 'none' | 'all' | 'content';\n"],"mappings":""}
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.isDateRangeCue = isDateRangeCue;
7
+ /**
8
+ * Represents a cue of a HLS date range metadata text track.
9
+ *
10
+ * @public
11
+ */
12
+
13
+ /**
14
+ * Check whether a text track cue is of type DateRangeCue.
15
+ */
16
+ function isDateRangeCue(cue) {
17
+ return cue.customAttributes != undefined;
18
+ }
19
+ //# sourceMappingURL=DateRangeCue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["isDateRangeCue","cue","customAttributes","undefined"],"sources":["DateRangeCue.ts"],"sourcesContent":["import type { TextTrackCue } from './TextTrackCue';\n\n/**\n * Represents a cue of a HLS date range metadata text track.\n *\n * @public\n */\nexport interface DateRangeCue extends TextTrackCue {\n /**\n * The class of the date range cue.\n *\n * @remarks\n * <br/> - The class is a client-defined string specifying a set of attributes with associated value semantics.\n */\n class: string | undefined;\n\n /**\n * The playback position at which the date range cue becomes active, as a Date.\n */\n startDate: Date;\n\n /**\n * The playback position at which the date range cue becomes inactive, as a Date.\n */\n endDate: Date | undefined;\n\n /**\n * The duration of the date range cue, in milliseconds.\n */\n duration: number | undefined;\n\n /**\n * The planned duration of the date range cue, in milliseconds.\n *\n * @remarks\n * <br/> - This is used when the exact duration is not known yet.\n */\n plannedDuration: number | undefined;\n\n /**\n * Whether end-on-next is enabled for the date range cue.\n *\n * @remarks\n * <br/> - End-on-next results in the {@link DateRangeCue.endDate} of the date range cue becoming equal to the {@link DateRangeCue.startDate} of the next date range cue with the same {@link DateRangeCue.\"class\"}, once it is known.\n */\n endOnNext: boolean;\n\n /**\n * The SCTE 'cmd' splice_info_section of the date range cue.\n */\n scte35Cmd: ArrayBuffer | undefined;\n\n /**\n * The SCTE 'out' splice_info_section of the date range cue.\n */\n scte35Out: ArrayBuffer | undefined;\n\n /**\n * The SCTE 'in' splice_info_section of the date range cue.\n */\n scte35In: ArrayBuffer | undefined;\n\n /**\n * Custom attributes extracted from the cue source.\n */\n customAttributes: Record<string, string | number | ArrayBuffer>;\n}\n\n/**\n * Check whether a text track cue is of type DateRangeCue.\n */\nexport function isDateRangeCue(cue: TextTrackCue): cue is DateRangeCue {\n return (cue as DateRangeCue).customAttributes != undefined;\n}\n"],"mappings":";;;;;;AAEA;AACA;AACA;AACA;AACA;;AA8DA;AACA;AACA;AACO,SAASA,cAAcA,CAACC,GAAiB,EAAuB;EACrE,OAAQA,GAAG,CAAkBC,gBAAgB,IAAIC,SAAS;AAC5D"}
@@ -17,6 +17,8 @@ let TextTrackType = exports.TextTrackType = /*#__PURE__*/function (TextTrackType
17
17
  TextTrackType["srt"] = "srt";
18
18
  TextTrackType["ttml"] = "ttml";
19
19
  TextTrackType["webvtt"] = "webvtt";
20
+ TextTrackType["daterange"] = "daterange";
21
+ TextTrackType["eventstream"] = "eventstream";
20
22
  return TextTrackType;
21
23
  }({});
22
24
  let TextTrackKind = exports.TextTrackKind = /*#__PURE__*/function (TextTrackKind) {
@@ -1 +1 @@
1
- {"version":3,"names":["TextTrackType","exports","TextTrackKind","TextTrackMode","filterRenderableTracks","textTracks","filter","textTrack","kind","filterThumbnailTracks","find","isThumbnailTrack","label","hasTextTrackCue","cue","cues","c","uid","removeTextTrackCue","addTextTrackCue","push","findTextTrackByUid","t"],"sources":["TextTrack.ts"],"sourcesContent":["import type { Track } from './Track';\nimport type { TextTrackCue } from './TextTrackCue';\n\nexport enum TextTrackType {\n cea608 = 'cea608',\n id3 = 'id3',\n srt = 'srt',\n ttml = 'ttml',\n webvtt = 'webvtt',\n}\n\nexport enum TextTrackKind {\n captions = 'captions',\n chapters = 'chapters',\n descriptions = 'descriptions',\n metadata = 'metadata',\n subtitles = 'subtitles',\n thumbnails = 'thumbnails',\n}\n\nexport enum TextTrackMode {\n disabled = 'disabled',\n showing = 'showing',\n hidden = 'hidden',\n}\n\nexport interface TextTrack extends Track {\n /**\n * The kind of the text track, represented by a value from the following list:\n * <br/> - `'subtitles'`: The track contains subtitles.\n * <br/> - `'captions'`: The track contains closed captions, a translation of dialogue and sound effects.\n * <br/> - `'descriptions'`: The track contains descriptions, a textual description of the video.\n * <br/> - `'chapters'`: The track contains chapter titles.\n * <br/> - `'metadata'`: The track contains metadata. This track will not serve display purposes.\n */\n readonly kind: TextTrackKind;\n\n /**\n * The label of the text track.\n */\n readonly label: string;\n\n /**\n * The language of the text track.\n */\n readonly language: string;\n\n /**\n * The identifier of the text track.\n *\n * @remarks\n * <br/> - This identifier can be used to distinguish between related tracks, e.g. tracks in the same list.\n */\n readonly id: string;\n\n /**\n * A unique identifier of the text track.\n *\n * @remarks\n * <br/> - This identifier is unique across tracks of a THEOplayer instance and can be used to distinguish between tracks.\n */\n readonly uid: number;\n\n /**\n * The mode of the text track, represented by a value from the following list:\n * <br/> - `'disabled'`: The track is disabled.\n * <br/> - `'showing'`: The track is showing.\n */\n mode: TextTrackMode;\n\n /**\n * The content type of the text track.\n */\n readonly type: TextTrackType;\n\n /**\n * The list of cues of the track.\n *\n * @remarks\n * <br/> - If the {@link TextTrack.mode} is `'disabled'`, this property is `null`.\n */\n cues: TextTrackCue[] | null;\n\n /**\n * The source of the text track.\n */\n readonly src: string;\n\n /**\n * Indicates whether the track contains Forced Narrative cues.\n * This may only be true for subtitle tracks where\n * <br/> - For DASH: the corresponding AdaptationSet contains a child Role with its value attribute equal to `'forced_subtitle'`\n * <br/> - For HLS: the corresponding #EXT-X-MEDIA tag contains the attributes TYPE=SUBTITLES and FORCED=YES (not supported yet)\n */\n readonly forced: boolean;\n}\n\n/**\n * Retain renderable tracks.\n * https://html.spec.whatwg.org/multipage/embedded-content.html#text-track-showing\n */\nexport function filterRenderableTracks(textTracks: TextTrack[] | undefined): TextTrack[] | undefined {\n return textTracks && textTracks.filter((textTrack) => textTrack.kind === 'subtitles' || textTrack.kind === 'captions');\n}\n\n/**\n * Retain first thumbnail track encountered in the textTracks list.\n */\nexport function filterThumbnailTracks(textTracks: TextTrack[] | undefined): TextTrack | undefined {\n return textTracks && textTracks.find(isThumbnailTrack);\n}\n\n/**\n * Query whether a track is a valid thumbnail track.\n */\nexport function isThumbnailTrack(textTrack: TextTrack | undefined): boolean {\n return !!textTrack && (textTrack.kind === 'thumbnails' || (textTrack.kind === 'metadata' && textTrack.label === 'thumbnails'));\n}\n\nexport function hasTextTrackCue(textTrack: TextTrack, cue: TextTrackCue): boolean {\n return !!(textTrack.cues && cue && textTrack.cues.find((c) => cue.uid === c.uid));\n}\n\nexport function removeTextTrackCue(textTrack?: TextTrack, cue?: TextTrackCue) {\n if (textTrack && textTrack.cues && cue && hasTextTrackCue(textTrack, cue)) {\n textTrack.cues = textTrack.cues.filter((c) => c.uid !== cue.uid);\n }\n}\n\nexport function addTextTrackCue(textTrack?: TextTrack, cue?: TextTrackCue) {\n if (textTrack && textTrack.cues && cue && !hasTextTrackCue(textTrack, cue)) {\n textTrack.cues.push(cue);\n }\n}\n\nexport function findTextTrackByUid(textTracks: TextTrack[], uid: number): TextTrack | undefined {\n return textTracks.find((t) => t.uid === uid);\n}\n"],"mappings":";;;;;;;;;;;;;IAGYA,aAAa,GAAAC,OAAA,CAAAD,aAAA,0BAAbA,aAAa;EAAbA,aAAa;EAAbA,aAAa;EAAbA,aAAa;EAAbA,aAAa;EAAbA,aAAa;EAAA,OAAbA,aAAa;AAAA;AAAA,IAQbE,aAAa,GAAAD,OAAA,CAAAC,aAAA,0BAAbA,aAAa;EAAbA,aAAa;EAAbA,aAAa;EAAbA,aAAa;EAAbA,aAAa;EAAbA,aAAa;EAAbA,aAAa;EAAA,OAAbA,aAAa;AAAA;AAAA,IASbC,aAAa,GAAAF,OAAA,CAAAE,aAAA,0BAAbA,aAAa;EAAbA,aAAa;EAAbA,aAAa;EAAbA,aAAa;EAAA,OAAbA,aAAa;AAAA;AA6EzB;AACA;AACA;AACA;AACO,SAASC,sBAAsBA,CAACC,UAAmC,EAA2B;EACnG,OAAOA,UAAU,IAAIA,UAAU,CAACC,MAAM,CAAEC,SAAS,IAAKA,SAAS,CAACC,IAAI,KAAK,WAAW,IAAID,SAAS,CAACC,IAAI,KAAK,UAAU,CAAC;AACxH;;AAEA;AACA;AACA;AACO,SAASC,qBAAqBA,CAACJ,UAAmC,EAAyB;EAChG,OAAOA,UAAU,IAAIA,UAAU,CAACK,IAAI,CAACC,gBAAgB,CAAC;AACxD;;AAEA;AACA;AACA;AACO,SAASA,gBAAgBA,CAACJ,SAAgC,EAAW;EAC1E,OAAO,CAAC,CAACA,SAAS,KAAKA,SAAS,CAACC,IAAI,KAAK,YAAY,IAAKD,SAAS,CAACC,IAAI,KAAK,UAAU,IAAID,SAAS,CAACK,KAAK,KAAK,YAAa,CAAC;AAChI;AAEO,SAASC,eAAeA,CAACN,SAAoB,EAAEO,GAAiB,EAAW;EAChF,OAAO,CAAC,EAAEP,SAAS,CAACQ,IAAI,IAAID,GAAG,IAAIP,SAAS,CAACQ,IAAI,CAACL,IAAI,CAAEM,CAAC,IAAKF,GAAG,CAACG,GAAG,KAAKD,CAAC,CAACC,GAAG,CAAC,CAAC;AACnF;AAEO,SAASC,kBAAkBA,CAACX,SAAqB,EAAEO,GAAkB,EAAE;EAC5E,IAAIP,SAAS,IAAIA,SAAS,CAACQ,IAAI,IAAID,GAAG,IAAID,eAAe,CAACN,SAAS,EAAEO,GAAG,CAAC,EAAE;IACzEP,SAAS,CAACQ,IAAI,GAAGR,SAAS,CAACQ,IAAI,CAACT,MAAM,CAAEU,CAAC,IAAKA,CAAC,CAACC,GAAG,KAAKH,GAAG,CAACG,GAAG,CAAC;EAClE;AACF;AAEO,SAASE,eAAeA,CAACZ,SAAqB,EAAEO,GAAkB,EAAE;EACzE,IAAIP,SAAS,IAAIA,SAAS,CAACQ,IAAI,IAAID,GAAG,IAAI,CAACD,eAAe,CAACN,SAAS,EAAEO,GAAG,CAAC,EAAE;IAC1EP,SAAS,CAACQ,IAAI,CAACK,IAAI,CAACN,GAAG,CAAC;EAC1B;AACF;AAEO,SAASO,kBAAkBA,CAAChB,UAAuB,EAAEY,GAAW,EAAyB;EAC9F,OAAOZ,UAAU,CAACK,IAAI,CAAEY,CAAC,IAAKA,CAAC,CAACL,GAAG,KAAKA,GAAG,CAAC;AAC9C"}
1
+ {"version":3,"names":["TextTrackType","exports","TextTrackKind","TextTrackMode","filterRenderableTracks","textTracks","filter","textTrack","kind","filterThumbnailTracks","find","isThumbnailTrack","label","hasTextTrackCue","cue","cues","c","uid","removeTextTrackCue","addTextTrackCue","push","findTextTrackByUid","t"],"sources":["TextTrack.ts"],"sourcesContent":["import type { Track } from './Track';\nimport type { TextTrackCue } from './TextTrackCue';\n\nexport enum TextTrackType {\n cea608 = 'cea608',\n id3 = 'id3',\n srt = 'srt',\n ttml = 'ttml',\n webvtt = 'webvtt',\n daterange = 'daterange',\n eventstream = 'eventstream',\n}\n\nexport enum TextTrackKind {\n captions = 'captions',\n chapters = 'chapters',\n descriptions = 'descriptions',\n metadata = 'metadata',\n subtitles = 'subtitles',\n thumbnails = 'thumbnails',\n}\n\nexport enum TextTrackMode {\n disabled = 'disabled',\n showing = 'showing',\n hidden = 'hidden',\n}\n\nexport interface TextTrack extends Track {\n /**\n * The kind of the text track, represented by a value from the following list:\n * <br/> - `'subtitles'`: The track contains subtitles.\n * <br/> - `'captions'`: The track contains closed captions, a translation of dialogue and sound effects.\n * <br/> - `'descriptions'`: The track contains descriptions, a textual description of the video.\n * <br/> - `'chapters'`: The track contains chapter titles.\n * <br/> - `'metadata'`: The track contains metadata. This track will not serve display purposes.\n */\n readonly kind: TextTrackKind;\n\n /**\n * The label of the text track.\n */\n readonly label: string;\n\n /**\n * The language of the text track.\n */\n readonly language: string;\n\n /**\n * The identifier of the text track.\n *\n * @remarks\n * <br/> - This identifier can be used to distinguish between related tracks, e.g. tracks in the same list.\n */\n readonly id: string;\n\n /**\n * A unique identifier of the text track.\n *\n * @remarks\n * <br/> - This identifier is unique across tracks of a THEOplayer instance and can be used to distinguish between tracks.\n */\n readonly uid: number;\n\n /**\n * The mode of the text track, represented by a value from the following list:\n * <br/> - `'disabled'`: The track is disabled.\n * <br/> - `'showing'`: The track is showing.\n * <br/> - `'hidden'`: The track is enabled and loading cues, but not shown. (used for metadata tracks)\n */\n mode: TextTrackMode;\n\n /**\n * The content type of the text track.\n */\n readonly type: TextTrackType;\n\n /**\n * The list of cues of the track.\n *\n * @remarks\n * <br/> - If the {@link TextTrack.mode} is `'disabled'`, this property is `null`.\n */\n cues: TextTrackCue[] | null;\n\n /**\n * The source of the text track.\n */\n readonly src: string;\n\n /**\n * Indicates whether the track contains Forced Narrative cues.\n * This may only be true for subtitle tracks where\n * <br/> - For DASH: the corresponding AdaptationSet contains a child Role with its value attribute equal to `'forced_subtitle'`\n * <br/> - For HLS: the corresponding #EXT-X-MEDIA tag contains the attributes TYPE=SUBTITLES and FORCED=YES (not supported yet)\n */\n readonly forced: boolean;\n}\n\n/**\n * Retain renderable tracks.\n * https://html.spec.whatwg.org/multipage/embedded-content.html#text-track-showing\n */\nexport function filterRenderableTracks(textTracks: TextTrack[] | undefined): TextTrack[] | undefined {\n return textTracks && textTracks.filter((textTrack) => textTrack.kind === 'subtitles' || textTrack.kind === 'captions');\n}\n\n/**\n * Retain first thumbnail track encountered in the textTracks list.\n */\nexport function filterThumbnailTracks(textTracks: TextTrack[] | undefined): TextTrack | undefined {\n return textTracks && textTracks.find(isThumbnailTrack);\n}\n\n/**\n * Query whether a track is a valid thumbnail track.\n */\nexport function isThumbnailTrack(textTrack: TextTrack | undefined): boolean {\n return !!textTrack && (textTrack.kind === 'thumbnails' || (textTrack.kind === 'metadata' && textTrack.label === 'thumbnails'));\n}\n\nexport function hasTextTrackCue(textTrack: TextTrack, cue: TextTrackCue): boolean {\n return !!(textTrack.cues && cue && textTrack.cues.find((c) => cue.uid === c.uid));\n}\n\nexport function removeTextTrackCue(textTrack?: TextTrack, cue?: TextTrackCue) {\n if (textTrack && textTrack.cues && cue && hasTextTrackCue(textTrack, cue)) {\n textTrack.cues = textTrack.cues.filter((c) => c.uid !== cue.uid);\n }\n}\n\nexport function addTextTrackCue(textTrack?: TextTrack, cue?: TextTrackCue) {\n if (textTrack && textTrack.cues && cue && !hasTextTrackCue(textTrack, cue)) {\n textTrack.cues.push(cue);\n }\n}\n\nexport function findTextTrackByUid(textTracks: TextTrack[], uid: number): TextTrack | undefined {\n return textTracks.find((t) => t.uid === uid);\n}\n"],"mappings":";;;;;;;;;;;;;IAGYA,aAAa,GAAAC,OAAA,CAAAD,aAAA,0BAAbA,aAAa;EAAbA,aAAa;EAAbA,aAAa;EAAbA,aAAa;EAAbA,aAAa;EAAbA,aAAa;EAAbA,aAAa;EAAbA,aAAa;EAAA,OAAbA,aAAa;AAAA;AAAA,IAUbE,aAAa,GAAAD,OAAA,CAAAC,aAAA,0BAAbA,aAAa;EAAbA,aAAa;EAAbA,aAAa;EAAbA,aAAa;EAAbA,aAAa;EAAbA,aAAa;EAAbA,aAAa;EAAA,OAAbA,aAAa;AAAA;AAAA,IASbC,aAAa,GAAAF,OAAA,CAAAE,aAAA,0BAAbA,aAAa;EAAbA,aAAa;EAAbA,aAAa;EAAbA,aAAa;EAAA,OAAbA,aAAa;AAAA;AA8EzB;AACA;AACA;AACA;AACO,SAASC,sBAAsBA,CAACC,UAAmC,EAA2B;EACnG,OAAOA,UAAU,IAAIA,UAAU,CAACC,MAAM,CAAEC,SAAS,IAAKA,SAAS,CAACC,IAAI,KAAK,WAAW,IAAID,SAAS,CAACC,IAAI,KAAK,UAAU,CAAC;AACxH;;AAEA;AACA;AACA;AACO,SAASC,qBAAqBA,CAACJ,UAAmC,EAAyB;EAChG,OAAOA,UAAU,IAAIA,UAAU,CAACK,IAAI,CAACC,gBAAgB,CAAC;AACxD;;AAEA;AACA;AACA;AACO,SAASA,gBAAgBA,CAACJ,SAAgC,EAAW;EAC1E,OAAO,CAAC,CAACA,SAAS,KAAKA,SAAS,CAACC,IAAI,KAAK,YAAY,IAAKD,SAAS,CAACC,IAAI,KAAK,UAAU,IAAID,SAAS,CAACK,KAAK,KAAK,YAAa,CAAC;AAChI;AAEO,SAASC,eAAeA,CAACN,SAAoB,EAAEO,GAAiB,EAAW;EAChF,OAAO,CAAC,EAAEP,SAAS,CAACQ,IAAI,IAAID,GAAG,IAAIP,SAAS,CAACQ,IAAI,CAACL,IAAI,CAAEM,CAAC,IAAKF,GAAG,CAACG,GAAG,KAAKD,CAAC,CAACC,GAAG,CAAC,CAAC;AACnF;AAEO,SAASC,kBAAkBA,CAACX,SAAqB,EAAEO,GAAkB,EAAE;EAC5E,IAAIP,SAAS,IAAIA,SAAS,CAACQ,IAAI,IAAID,GAAG,IAAID,eAAe,CAACN,SAAS,EAAEO,GAAG,CAAC,EAAE;IACzEP,SAAS,CAACQ,IAAI,GAAGR,SAAS,CAACQ,IAAI,CAACT,MAAM,CAAEU,CAAC,IAAKA,CAAC,CAACC,GAAG,KAAKH,GAAG,CAACG,GAAG,CAAC;EAClE;AACF;AAEO,SAASE,eAAeA,CAACZ,SAAqB,EAAEO,GAAkB,EAAE;EACzE,IAAIP,SAAS,IAAIA,SAAS,CAACQ,IAAI,IAAID,GAAG,IAAI,CAACD,eAAe,CAACN,SAAS,EAAEO,GAAG,CAAC,EAAE;IAC1EP,SAAS,CAACQ,IAAI,CAACK,IAAI,CAACN,GAAG,CAAC;EAC1B;AACF;AAEO,SAASO,kBAAkBA,CAAChB,UAAuB,EAAEY,GAAW,EAAyB;EAC9F,OAAOZ,UAAU,CAACK,IAAI,CAAEY,CAAC,IAAKA,CAAC,CAACL,GAAG,KAAKA,GAAG,CAAC;AAC9C"}
@@ -69,4 +69,15 @@ Object.keys(_TextTrackStyle).forEach(function (key) {
69
69
  }
70
70
  });
71
71
  });
72
+ var _DateRangeCue = require("./DateRangeCue");
73
+ Object.keys(_DateRangeCue).forEach(function (key) {
74
+ if (key === "default" || key === "__esModule") return;
75
+ if (key in exports && exports[key] === _DateRangeCue[key]) return;
76
+ Object.defineProperty(exports, key, {
77
+ enumerable: true,
78
+ get: function () {
79
+ return _DateRangeCue[key];
80
+ }
81
+ });
82
+ });
72
83
  //# sourceMappingURL=barrel.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["_MediaTrack","require","Object","keys","forEach","key","exports","defineProperty","enumerable","get","_Quality","_TextTrack","_TextTrackCue","_Track","_TextTrackStyle"],"sources":["barrel.ts"],"sourcesContent":["export * from './MediaTrack';\nexport * from './Quality';\nexport * from './TextTrack';\nexport * from './TextTrackCue';\nexport * from './Track';\nexport * from './TextTrackStyle';\n"],"mappings":";;;;;AAAA,IAAAA,WAAA,GAAAC,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAH,WAAA,EAAAI,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAL,WAAA,CAAAK,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAT,WAAA,CAAAK,GAAA;IAAA;EAAA;AAAA;AACA,IAAAK,QAAA,GAAAT,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAO,QAAA,EAAAN,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAK,QAAA,CAAAL,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAC,QAAA,CAAAL,GAAA;IAAA;EAAA;AAAA;AACA,IAAAM,UAAA,GAAAV,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAQ,UAAA,EAAAP,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAM,UAAA,CAAAN,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAE,UAAA,CAAAN,GAAA;IAAA;EAAA;AAAA;AACA,IAAAO,aAAA,GAAAX,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAS,aAAA,EAAAR,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAO,aAAA,CAAAP,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAG,aAAA,CAAAP,GAAA;IAAA;EAAA;AAAA;AACA,IAAAQ,MAAA,GAAAZ,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAU,MAAA,EAAAT,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAQ,MAAA,CAAAR,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAI,MAAA,CAAAR,GAAA;IAAA;EAAA;AAAA;AACA,IAAAS,eAAA,GAAAb,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAW,eAAA,EAAAV,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAS,eAAA,CAAAT,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAK,eAAA,CAAAT,GAAA;IAAA;EAAA;AAAA"}
1
+ {"version":3,"names":["_MediaTrack","require","Object","keys","forEach","key","exports","defineProperty","enumerable","get","_Quality","_TextTrack","_TextTrackCue","_Track","_TextTrackStyle","_DateRangeCue"],"sources":["barrel.ts"],"sourcesContent":["export * from './MediaTrack';\nexport * from './Quality';\nexport * from './TextTrack';\nexport * from './TextTrackCue';\nexport * from './Track';\nexport * from './TextTrackStyle';\nexport * from './DateRangeCue';\n"],"mappings":";;;;;AAAA,IAAAA,WAAA,GAAAC,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAH,WAAA,EAAAI,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAL,WAAA,CAAAK,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAT,WAAA,CAAAK,GAAA;IAAA;EAAA;AAAA;AACA,IAAAK,QAAA,GAAAT,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAO,QAAA,EAAAN,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAK,QAAA,CAAAL,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAC,QAAA,CAAAL,GAAA;IAAA;EAAA;AAAA;AACA,IAAAM,UAAA,GAAAV,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAQ,UAAA,EAAAP,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAM,UAAA,CAAAN,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAE,UAAA,CAAAN,GAAA;IAAA;EAAA;AAAA;AACA,IAAAO,aAAA,GAAAX,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAS,aAAA,EAAAR,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAO,aAAA,CAAAP,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAG,aAAA,CAAAP,GAAA;IAAA;EAAA;AAAA;AACA,IAAAQ,MAAA,GAAAZ,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAU,MAAA,EAAAT,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAQ,MAAA,CAAAR,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAI,MAAA,CAAAR,GAAA;IAAA;EAAA;AAAA;AACA,IAAAS,eAAA,GAAAb,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAW,eAAA,EAAAV,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAS,eAAA,CAAAT,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAK,eAAA,CAAAT,GAAA;IAAA;EAAA;AAAA;AACA,IAAAU,aAAA,GAAAd,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAY,aAAA,EAAAX,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAU,aAAA,CAAAV,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAM,aAAA,CAAAV,GAAA;IAAA;EAAA;AAAA"}
@@ -112,8 +112,7 @@ class THEOplayerView extends _react.PureComponent {
112
112
  const nativeEvent = event.nativeEvent;
113
113
  const cue = nativeEvent.cue;
114
114
  if (cue) {
115
- cue.startTime = (0, _TypeUtils.decodeNanInf)(cue.startTime);
116
- cue.endTime = (0, _TypeUtils.decodeNanInf)(cue.endTime);
115
+ this.normalizeCue(cue);
117
116
  }
118
117
  this._facade.dispatchEvent(new _PlayerEvents.DefaultTextTrackEvent((0, _NativeTrackEvent.toTextTrackEventType)(nativeEvent.type), nativeEvent.trackUid, cue));
119
118
  });
@@ -172,6 +171,22 @@ class THEOplayerView extends _react.PureComponent {
172
171
  reset() {
173
172
  this.setState(THEOplayerView.initialState);
174
173
  }
174
+ normalizeCue(cue) {
175
+ cue.startTime = (0, _TypeUtils.decodeNanInf)(cue.startTime);
176
+ cue.endTime = (0, _TypeUtils.decodeNanInf)(cue.endTime);
177
+ if ((0, _reactNativeTheoplayer.isDateRangeCue)(cue)) {
178
+ cue.startDate = new Date(cue.startDate);
179
+ if (cue.endDate) {
180
+ cue.endDate = new Date(cue.endDate);
181
+ }
182
+ if (cue.duration) {
183
+ cue.duration = (0, _TypeUtils.decodeNanInf)(cue.duration);
184
+ }
185
+ if (cue.plannedDuration) {
186
+ cue.plannedDuration = (0, _TypeUtils.decodeNanInf)(cue.plannedDuration);
187
+ }
188
+ }
189
+ }
175
190
  render() {
176
191
  const {
177
192
  config,