@jwplayer/jwplayer-react-native 1.0.1 → 1.0.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.
Files changed (58) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.md +10 -0
  2. package/.github/ISSUE_TEMPLATE/feature_request.md +10 -0
  3. package/.github/ISSUE_TEMPLATE/implement.md +9 -0
  4. package/.github/ISSUE_TEMPLATE/question.md +10 -0
  5. package/README.md +2 -0
  6. package/RNJWPlayer.podspec +2 -2
  7. package/android/.gradle/8.9/checksums/checksums.lock +0 -0
  8. package/android/.gradle/8.9/fileHashes/fileHashes.lock +0 -0
  9. package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
  10. package/android/.gradle/buildOutputCleanup/cache.properties +2 -2
  11. package/android/build.gradle +1 -1
  12. package/android/src/main/AndroidManifest.xml +2 -0
  13. package/android/src/main/java/com/jwplayer/rnjwplayer/RNJWPlayerModule.java +510 -458
  14. package/android/src/main/java/com/jwplayer/rnjwplayer/RNJWPlayerView.java +384 -32
  15. package/android/src/main/java/com/jwplayer/rnjwplayer/RNJWPlayerViewManager.java +12 -0
  16. package/android/src/main/java/com/jwplayer/rnjwplayer/Util.java +26 -7
  17. package/badges/version.svg +1 -1
  18. package/index.d.ts +41 -7
  19. package/index.js +22 -2
  20. package/ios/RNJWPlayer/RNJWPlayerView.swift +47 -34
  21. package/ios/RNJWPlayer/RNJWPlayerViewController.swift +15 -9
  22. package/ios/RNJWPlayer/RNJWPlayerViewManager.m +9 -1
  23. package/ios/RNJWPlayer/RNJWPlayerViewManager.swift +49 -15
  24. package/jwplayer-jwplayer-react-native-1.0.3.tgz +0 -0
  25. package/package.json +3 -3
  26. package/.idea/modules.xml +0 -8
  27. package/.idea/vcs.xml +0 -6
  28. package/android/.gradle/8.1.1/checksums/checksums.lock +0 -0
  29. package/android/.gradle/8.1.1/checksums/md5-checksums.bin +0 -0
  30. package/android/.gradle/8.1.1/checksums/sha1-checksums.bin +0 -0
  31. package/android/.gradle/8.1.1/dependencies-accessors/dependencies-accessors.lock +0 -0
  32. package/android/.gradle/8.1.1/fileHashes/fileHashes.lock +0 -0
  33. package/android/.gradle/8.4/checksums/checksums.lock +0 -0
  34. package/android/.gradle/8.4/checksums/md5-checksums.bin +0 -0
  35. package/android/.gradle/8.4/checksums/sha1-checksums.bin +0 -0
  36. package/android/.gradle/8.4/dependencies-accessors/dependencies-accessors.lock +0 -0
  37. package/android/.gradle/8.4/dependencies-accessors/gc.properties +0 -0
  38. package/android/.gradle/8.4/executionHistory/executionHistory.bin +0 -0
  39. package/android/.gradle/8.4/executionHistory/executionHistory.lock +0 -0
  40. package/android/.gradle/8.4/fileChanges/last-build.bin +0 -0
  41. package/android/.gradle/8.4/fileHashes/fileHashes.bin +0 -0
  42. package/android/.gradle/8.4/fileHashes/fileHashes.lock +0 -0
  43. package/android/.gradle/8.4/gc.properties +0 -0
  44. package/android/.gradle/config.properties +0 -2
  45. package/android/.gradle/file-system.probe +0 -0
  46. package/android/.idea/compiler.xml +0 -6
  47. package/android/.idea/gradle.xml +0 -18
  48. package/android/.idea/migrations.xml +0 -10
  49. package/android/.idea/misc.xml +0 -10
  50. package/android/.idea/vcs.xml +0 -6
  51. package/android/local.properties +0 -8
  52. package/ios/RNJWPlayer.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -7
  53. package/ios/RNJWPlayer.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +0 -8
  54. package/ios/RNJWPlayer.xcodeproj/project.xcworkspace/xcuserdata/jmilham.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  55. package/ios/RNJWPlayer.xcodeproj/xcuserdata/jmilham.xcuserdatad/xcschemes/xcschememanagement.plist +0 -14
  56. /package/android/.gradle/{8.1.1 → 8.9}/dependencies-accessors/gc.properties +0 -0
  57. /package/android/.gradle/{8.1.1 → 8.9}/fileChanges/last-build.bin +0 -0
  58. /package/android/.gradle/{8.1.1 → 8.9}/gc.properties +0 -0
@@ -155,10 +155,22 @@ public class RNJWPlayerViewManager extends SimpleViewManager<RNJWPlayerView> {
155
155
  MapBuilder.of(
156
156
  "phasedRegistrationNames",
157
157
  MapBuilder.of("bubbled", "onAudioTracks")))
158
+ .put("topCaptionsChanged",
159
+ MapBuilder.of(
160
+ "phasedRegistrationNames",
161
+ MapBuilder.of("bubbled", "onCaptionsChanged")))
162
+ .put("topCaptionsList",
163
+ MapBuilder.of(
164
+ "phasedRegistrationNames",
165
+ MapBuilder.of("bubbled", "onCaptionsList")))
158
166
  .put("topCasting",
159
167
  MapBuilder.of(
160
168
  "phasedRegistrationNames",
161
169
  MapBuilder.of("bubbled", "onCasting")))
170
+ .put("topFirstFrame",
171
+ MapBuilder.of(
172
+ "phasedRegistrationNames",
173
+ MapBuilder.of("bubbled", "onLoaded")))
162
174
  .build();
163
175
  }
164
176
 
@@ -2,17 +2,21 @@ package com.jwplayer.rnjwplayer;
2
2
 
3
3
  import static androidx.media3.common.util.Util.toByteArray;
4
4
 
5
+ import android.util.Log;
5
6
  import android.util.Patterns;
6
7
  import android.webkit.URLUtil;
7
8
 
8
9
  import com.facebook.react.bridge.ReadableArray;
9
10
  import com.facebook.react.bridge.ReadableMap;
11
+ import com.jwplayer.pub.api.JsonHelper;
10
12
  import com.jwplayer.pub.api.media.ads.AdBreak;
11
13
  import com.jwplayer.pub.api.media.captions.Caption;
12
14
  import com.jwplayer.pub.api.media.captions.CaptionType;
13
15
  import com.jwplayer.pub.api.media.playlists.MediaSource;
14
16
  import com.jwplayer.pub.api.media.playlists.PlaylistItem;
15
17
 
18
+ import org.json.JSONObject;
19
+
16
20
  import java.io.IOException;
17
21
  import java.io.InputStream;
18
22
  import java.io.OutputStream;
@@ -20,8 +24,8 @@ import java.net.HttpURLConnection;
20
24
  import java.net.URL;
21
25
  import java.util.ArrayList;
22
26
  import java.util.List;
23
- import java.util.Map;
24
27
  import java.util.Locale;
28
+ import java.util.Map;
25
29
 
26
30
  public class Util {
27
31
 
@@ -62,7 +66,7 @@ public class Util {
62
66
  }
63
67
  }
64
68
 
65
- public static boolean isValidURL(String url){
69
+ public static boolean isValidURL(String url) {
66
70
  return URLUtil.isValidUrl(url) && Patterns.WEB_URL.matcher(url).matches();
67
71
  }
68
72
 
@@ -75,14 +79,28 @@ public class Util {
75
79
  while (playlistItems.size() > j) {
76
80
  ReadableMap playlistItem = playlistItems.getMap(j);
77
81
 
78
- PlaylistItem newPlayListItem = getPlaylistItem((playlistItem));
79
- playlist.add(newPlayListItem);
82
+ JSONObject obj;
83
+ PlaylistItem item = null;
84
+ // Try since legacy config may or may not conform to this standard
85
+ try {
86
+ obj = MapUtil.toJSONObject(playlistItem);
87
+ item = JsonHelper.parsePlaylistItemJson(obj);
88
+ } catch (Exception ex) {
89
+ Log.e("createPlaylist", ex.toString());
90
+ }
91
+ if (item != null) {
92
+ playlist.add(item);
93
+ } else {
94
+ // Try to use the legacy format
95
+ PlaylistItem newPlayListItem = getPlaylistItem((playlistItem));
96
+ playlist.add(newPlayListItem);
97
+ }
80
98
  j++;
81
99
  }
82
100
  return playlist;
83
101
  }
84
102
 
85
- public static PlaylistItem getPlaylistItem (ReadableMap playlistItem) {
103
+ public static PlaylistItem getPlaylistItem(ReadableMap playlistItem) {
86
104
  PlaylistItem.Builder itemBuilder = new PlaylistItem.Builder();
87
105
 
88
106
  if (playlistItem.hasKey("file")) {
@@ -194,11 +212,12 @@ public class Util {
194
212
 
195
213
  /**
196
214
  * Internal helper for parsing a caption type from a known string
215
+ *
197
216
  * @param type one of "CAPTIONS", "CHAPTERS", "THUMBNAILS"
198
217
  * @return the correct Enum CaptionType
199
218
  */
200
- public static CaptionType getCaptionType(String type){
201
- for (CaptionType captionType: CaptionType.values()) {
219
+ public static CaptionType getCaptionType(String type) {
220
+ for (CaptionType captionType : CaptionType.values()) {
202
221
  if (captionType.name().equals(type)) {
203
222
  return CaptionType.valueOf(type);
204
223
  }
@@ -1 +1 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="90" height="20" role="img" aria-label="version: 1.0.1"><title>version: 1.0.1</title><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="r"><rect width="90" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#r)"><rect width="51" height="20" fill="#555"/><rect x="51" width="39" height="20" fill="#007ec6"/><rect width="90" height="20" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><text aria-hidden="true" x="265" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="410">version</text><text x="265" y="140" transform="scale(.1)" fill="#fff" textLength="410">version</text><text aria-hidden="true" x="695" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="290">1.0.1</text><text x="695" y="140" transform="scale(.1)" fill="#fff" textLength="290">1.0.1</text></g></svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="90" height="20" role="img" aria-label="version: 1.0.3"><title>version: 1.0.3</title><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="r"><rect width="90" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#r)"><rect width="51" height="20" fill="#555"/><rect x="51" width="39" height="20" fill="#007ec6"/><rect width="90" height="20" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><text aria-hidden="true" x="265" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="410">version</text><text x="265" y="140" transform="scale(.1)" fill="#fff" textLength="410">version</text><text aria-hidden="true" x="695" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="290">1.0.3</text><text x="695" y="140" transform="scale(.1)" fill="#fff" textLength="290">1.0.3</text></g></svg>
package/index.d.ts CHANGED
@@ -26,7 +26,13 @@ declare module "@jwplayer/jwplayer-react-native" {
26
26
  advertising?: JwAdvertisingConfig;
27
27
  playbackRates?: number[];
28
28
  playbackRateControls?: boolean;
29
+ // Non-Json Parsing props
29
30
  license: string;
31
+ playerInModal?: boolean;
32
+ fullScreenOnLandscape?: boolean;
33
+ landscapeOnFullScreen?: boolean;
34
+ portraitOnExitFullScreen?: boolean;
35
+ exitFullScreenOnPortrait?: boolean;
30
36
  }
31
37
 
32
38
  type JwThumbnailPreview = 101 | 102 | 103;
@@ -448,6 +454,7 @@ declare module "@jwplayer/jwplayer-react-native" {
448
454
  landscapeOnFullScreen?: boolean;
449
455
  portraitOnExitFullScreen?: boolean;
450
456
  exitFullScreenOnPortrait?: boolean;
457
+ playerInModal?: boolean;
451
458
  playlist?: PlaylistItem[];
452
459
  stretching?: string;
453
460
  related?: Related;
@@ -476,6 +483,15 @@ declare module "@jwplayer/jwplayer-react-native" {
476
483
  rate: number;
477
484
  at: number;
478
485
  }
486
+ interface PlayerSetupErrorProps {
487
+ errorMessage?: string;
488
+ errorCode?: number;
489
+ }
490
+ interface PlayerErrorProps {
491
+ error?: string;
492
+ errorCode?: number;
493
+ description?: string; // Android Only
494
+ }
479
495
  interface TimeEventProps {
480
496
  position: number;
481
497
  duration: number;
@@ -486,6 +502,9 @@ declare module "@jwplayer/jwplayer-react-native" {
486
502
  interface PlaylistEventProps {
487
503
  playlist: PlaylistItem[]
488
504
  }
505
+ interface LoadEventProps {
506
+ loadTime: number;
507
+ }
489
508
  interface PlaylistItemEventProps {
490
509
  playlistItem: PlaylistItem
491
510
  }
@@ -494,15 +513,26 @@ declare module "@jwplayer/jwplayer-react-native" {
494
513
  error: string;
495
514
  }
496
515
  interface PlayerWarningEventProps {
497
- code: string;
498
- warning: string;
516
+ code?: number;
517
+ warning?: string;
518
+ adErrorCode?: number; // Android only
499
519
  }
500
520
  interface AdEventProps {
501
521
  client?: string;
502
522
  reason?: string;
503
523
  type: number;
504
524
  }
505
- type NativeError = (event: BaseEvent<PlayerErrorEventProps>) => void;
525
+ // Overloaded type to be used in multiple error events
526
+ interface CaptionsChangedEventProps {
527
+ index?: number;
528
+ }
529
+ interface CaptionsListEventProps {
530
+ index: number;
531
+ file?: string;
532
+ label: string;
533
+ default: string;
534
+ }
535
+ type NativeError = (event: BaseEvent<PlayerErrorEventProps> | BaseEvent<PlayerSetupErrorProps> | BaseEvent<PlayerErrorProps>) => void;
506
536
  type NativeWarning = (event: BaseEvent<PlayerWarningEventProps>) => void;
507
537
  interface PropsType {
508
538
  config: Config | JwConfig;
@@ -511,6 +541,7 @@ declare module "@jwplayer/jwplayer-react-native" {
511
541
  forceLegacyConfig?: boolean;
512
542
  onPlayerReady?: () => void;
513
543
  onPlaylist?: (event: BaseEvent<PlaylistEventProps>) => void;
544
+ onLoaded? : (event: BaseEvent<LoadEventProps>) => void;
514
545
  onBeforePlay?: () => void;
515
546
  onBeforeComplete?: () => void;
516
547
  onComplete?: () => void;
@@ -521,9 +552,9 @@ declare module "@jwplayer/jwplayer-react-native" {
521
552
  onRateChanged?: (event?: BaseEvent<RateChangedEventProps>) => void;
522
553
  onSetupPlayerError?: NativeError;
523
554
  onPlayerError?: NativeError;
524
- onPlayerWarning?: NativeWarning;
525
- onPlayerAdError?: NativeError;
526
- onPlayerAdWarning?: NativeWarning;
555
+ onPlayerWarning?: NativeWarning;
556
+ onPlayerAdError?: NativeError;
557
+ onPlayerAdWarning?: NativeWarning;
527
558
  onAdEvent?: (event: BaseEvent<AdEventProps>) => void;
528
559
  onAdTime?: (event: BaseEvent<TimeEventProps>) => void;
529
560
  onBuffer?: () => void;
@@ -535,6 +566,8 @@ declare module "@jwplayer/jwplayer-react-native" {
535
566
  onControlBarVisible?: (event: BaseEvent<ControlBarVisibleEventProps>) => void;
536
567
  onPlaylistComplete?: () => void;
537
568
  onPlaylistItem?: (event: BaseEvent<PlaylistItemEventProps>) => void;
569
+ onCaptionsChanged?: (event: BaseEvent<CaptionsChangedEventProps>) => void;
570
+ onCaptionsList?: (event: BaseEvent<CaptionsListEventProps>) => void;
538
571
  onAudioTracks?: () => void;
539
572
  shouldComponentUpdate?: (nextProps: any, nextState: any) => boolean;
540
573
  }
@@ -553,7 +586,7 @@ declare module "@jwplayer/jwplayer-react-native" {
553
586
  setControls(show: boolean): void;
554
587
  setLockScreenControls(show: boolean): void;
555
588
  seekTo(time: number): void;
556
- loadPlaylist(playlistItems: PlaylistItem[]): void;
589
+ loadPlaylist(playlistItems: PlaylistItem[] | JwPlaylistItem[] | string): void;
557
590
  setFullscreen(fullScreen: boolean): void;
558
591
  position(): Promise<number>;
559
592
  setUpCastController(): void;
@@ -566,6 +599,7 @@ declare module "@jwplayer/jwplayer-react-native" {
566
599
  getCurrentAudioTrack(): Promise<number | null>;
567
600
  setCurrentAudioTrack(index: number): void;
568
601
  setCurrentCaptions(index: number): void;
602
+ getCurrentCaptions(): Promise<number | null>;
569
603
  setVisibility(visibility: boolean, controls: JWControlType[]): void;
570
604
  }
571
605
  }
package/index.js CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  findNodeHandle,
7
7
  } from 'react-native';
8
8
  import PropTypes from 'prop-types';
9
- import _ from 'lodash';
9
+ import isEqualWith from 'lodash.isequalwith';
10
10
 
11
11
  const RNJWPlayerManager =
12
12
  Platform.OS === 'ios'
@@ -306,6 +306,7 @@ export default class JWPlayer extends Component {
306
306
  offlineImage: PropTypes.string,
307
307
  forceFullScreenOnLandscape: PropTypes.bool,
308
308
  forceLandscapeOnFullScreen: PropTypes.bool,
309
+ playerInModal: PropTypes.bool,
309
310
  enableLockScreenControls: PropTypes.bool,
310
311
  stretching: PropTypes.oneOf([
311
312
  'uniform',
@@ -319,6 +320,7 @@ export default class JWPlayer extends Component {
319
320
  }),
320
321
  onPlayerReady: PropTypes.func,
321
322
  onPlaylist: PropTypes.func,
323
+ onLoaded: PropTypes.func,
322
324
  changePlaylist: PropTypes.func,
323
325
  play: PropTypes.func,
324
326
  pause: PropTypes.func,
@@ -368,6 +370,9 @@ export default class JWPlayer extends Component {
368
370
  getCurrentAudioTrack: PropTypes.func,
369
371
  setCurrentAudioTrack: PropTypes.func,
370
372
  setCurrentCaptions: PropTypes.func,
373
+ getCurrentCaptions: PropTypes.func,
374
+ onCaptionsChanged: PropTypes.func,
375
+ onCaptionsList: PropTypes.func,
371
376
  onAudioTracks: PropTypes.func,
372
377
  };
373
378
 
@@ -389,7 +394,7 @@ export default class JWPlayer extends Component {
389
394
  var { config, controls } = nextProps;
390
395
  var thisConfig = this.props.config || {};
391
396
 
392
- var result = !_.isEqualWith(
397
+ var result = !isEqualWith(
393
398
  config,
394
399
  thisConfig,
395
400
  (value1, value2, key) => {
@@ -686,6 +691,21 @@ export default class JWPlayer extends Component {
686
691
  );
687
692
  }
688
693
  }
694
+
695
+ async getCurrentCaptions() {
696
+ if (RNJWPlayerManager) {
697
+ try {
698
+ var currentCaptionTrack =
699
+ await RNJWPlayerManager.getCurrentCaptions(
700
+ this.getRNJWPlayerBridgeHandle()
701
+ );
702
+ return currentCaptionTrack;
703
+ } catch (e) {
704
+ console.error(e);
705
+ return null;
706
+ }
707
+ }
708
+ }
689
709
 
690
710
  getRNJWPlayerBridgeHandle() {
691
711
  return findNodeHandle(this[this.ref_key]);
@@ -85,6 +85,8 @@ class RNJWPlayerView : UIView, JWPlayerDelegate, JWPlayerStateDelegate, JWAdDele
85
85
  @objc var onCasting: RCTDirectEventBlock?
86
86
  @objc var onCastingEnded: RCTDirectEventBlock?
87
87
  @objc var onCastingFailed: RCTDirectEventBlock?
88
+ @objc var onCaptionsChanged: RCTDirectEventBlock?
89
+ @objc var onCaptionsList: RCTDirectEventBlock?
88
90
 
89
91
  init() {
90
92
  super.init(frame: CGRect(x: 20, y: 0, width: UIScreen.main.bounds.width - 40, height: 300))
@@ -299,7 +301,7 @@ class RNJWPlayerView : UIView, JWPlayerDelegate, JWPlayerStateDelegate, JWAdDele
299
301
  }
300
302
 
301
303
  if backgroundAudioEnabled || pipEnabled {
302
- let category = config["category"] as? String
304
+ let category = config["category"] != nil ? config["category"] as? String : "playback" // default category for playback
303
305
  let categoryOptions = config["categoryOptions"] as? [String]
304
306
  let mode = config["mode"] as? String
305
307
 
@@ -960,12 +962,12 @@ class RNJWPlayerView : UIView, JWPlayerDelegate, JWPlayerStateDelegate, JWAdDele
960
962
  }
961
963
 
962
964
  func jwplayer(_ player:JWPlayer, failedWithError code:UInt, message:String) {
963
- self.onPlayerError?(["error": message])
965
+ self.onPlayerError?(["error": message, "errorCode": code])
964
966
  playerFailed = true
965
967
  }
966
968
 
967
969
  func jwplayer(_ player:JWPlayer, failedWithSetupError code:UInt, message:String) {
968
- self.onSetupPlayerError?(["error": message])
970
+ self.onSetupPlayerError?(["errorMessage": message, "errorCode": code])
969
971
  playerFailed = true
970
972
  }
971
973
 
@@ -979,7 +981,7 @@ class RNJWPlayerView : UIView, JWPlayerDelegate, JWPlayerStateDelegate, JWAdDele
979
981
 
980
982
 
981
983
  func jwplayer(_ player:JWPlayer, encounteredAdWarning code:UInt, message:String) {
982
- self.onPlayerAdWarning?(["warning": message])
984
+ self.onPlayerAdWarning?(["warning": message, "code": code])
983
985
  }
984
986
 
985
987
 
@@ -1179,10 +1181,6 @@ class RNJWPlayerView : UIView, JWPlayerDelegate, JWPlayerStateDelegate, JWAdDele
1179
1181
 
1180
1182
  // MARK: - JWPlayer State Delegate
1181
1183
 
1182
- func jwplayerContentIsBuffering(_ player:JWPlayer) {
1183
- self.onBuffer?([:])
1184
- }
1185
-
1186
1184
  func jwplayer(_ player:JWPlayer, isBufferingWithReason reason:JWBufferReason) {
1187
1185
  self.onBuffer?([:])
1188
1186
  }
@@ -1192,7 +1190,7 @@ class RNJWPlayerView : UIView, JWPlayerDelegate, JWPlayerStateDelegate, JWAdDele
1192
1190
  }
1193
1191
 
1194
1192
  func jwplayer(_ player:JWPlayer, didFinishLoadingWithTime loadTime:TimeInterval) {
1195
- self.onLoaded?([:])
1193
+ self.onLoaded?(["loadTime":loadTime])
1196
1194
  }
1197
1195
 
1198
1196
  func jwplayer(_ player:JWPlayer, isAttemptingToPlay playlistItem:JWPlayerItem, reason:JWPlayReason) {
@@ -1233,6 +1231,10 @@ class RNJWPlayerView : UIView, JWPlayerDelegate, JWPlayerStateDelegate, JWAdDele
1233
1231
  func jwplayerContentDidComplete(_ player:JWPlayer) {
1234
1232
  self.onComplete?([:])
1235
1233
  }
1234
+
1235
+ func jwplayerContentIsBuffering(_ player: any JWPlayerKit.JWPlayer) {
1236
+
1237
+ }
1236
1238
 
1237
1239
  func jwplayer(_ player:JWPlayer, didLoadPlaylistItem item:JWPlayerItem, at index:UInt) {
1238
1240
  // var sourceDict: [String: Any] = [:]
@@ -1400,7 +1402,7 @@ class RNJWPlayerView : UIView, JWPlayerDelegate, JWPlayerStateDelegate, JWAdDele
1400
1402
  }
1401
1403
 
1402
1404
  func jwplayer(_ player:JWPlayer, captionTrackChanged index:Int) {
1403
-
1405
+ self.onCaptionsChanged?(["index": index])
1404
1406
  }
1405
1407
 
1406
1408
  func jwplayer(_ player: JWPlayer, visualQualityChanged currentVisualQuality: JWVisualQuality) {
@@ -1416,7 +1418,15 @@ class RNJWPlayerView : UIView, JWPlayerDelegate, JWPlayerStateDelegate, JWAdDele
1416
1418
  }
1417
1419
 
1418
1420
  func jwplayer(_ player:JWPlayer, updatedCaptionList options:[JWMediaSelectionOption]) {
1419
-
1421
+ var tracks: [[String: Any]] = []
1422
+ for track in player.captionsTracks {
1423
+ var dict: [String: Any] = [:]
1424
+ dict["label"] = track.name
1425
+ dict["default"] = track.defaultOption
1426
+ tracks.append(dict)
1427
+ }
1428
+ let currentIndex = player.currentCaptionsTrack
1429
+ self.onCaptionsList?(["index": currentIndex, "tracks": tracks])
1420
1430
  }
1421
1431
 
1422
1432
  // MARK: - JWPlayer audio session && interruption handling
@@ -1518,29 +1528,32 @@ class RNJWPlayerView : UIView, JWPlayerDelegate, JWPlayerStateDelegate, JWAdDele
1518
1528
  }
1519
1529
 
1520
1530
  var options: AVAudioSession.CategoryOptions = []
1521
- if categoryOptions.contains("MixWithOthers") {
1522
- options.insert(.mixWithOthers)
1523
- }
1524
- if categoryOptions.contains("DuckOthers") {
1525
- options.insert(.duckOthers)
1526
- }
1527
- if categoryOptions.contains("AllowBluetooth") {
1528
- options.insert(.allowBluetooth)
1529
- }
1530
- if categoryOptions.contains("InterruptSpokenAudioAndMix") {
1531
- options.insert(.interruptSpokenAudioAndMixWithOthers)
1532
- }
1533
- if categoryOptions.contains("AllowBluetoothA2DP") {
1534
- options.insert(.allowBluetoothA2DP)
1535
- }
1536
- if categoryOptions.contains("AllowAirPlay") {
1537
- options.insert(.allowAirPlay)
1538
- }
1539
- if categoryOptions.contains("OverrideMutedMicrophone") {
1540
- if #available(iOS 14.5, *) {
1541
- options.insert(.overrideMutedMicrophoneInterruption)
1542
- } else {
1543
- // Handle the case for earlier versions if needed
1531
+ // If the user doesn't specify any options
1532
+ if categoryOptions != nil {
1533
+ if categoryOptions.contains("MixWithOthers") {
1534
+ options.insert(.mixWithOthers)
1535
+ }
1536
+ if categoryOptions.contains("DuckOthers") {
1537
+ options.insert(.duckOthers)
1538
+ }
1539
+ if categoryOptions.contains("AllowBluetooth") {
1540
+ options.insert(.allowBluetooth)
1541
+ }
1542
+ if categoryOptions.contains("InterruptSpokenAudioAndMix") {
1543
+ options.insert(.interruptSpokenAudioAndMixWithOthers)
1544
+ }
1545
+ if categoryOptions.contains("AllowBluetoothA2DP") {
1546
+ options.insert(.allowBluetoothA2DP)
1547
+ }
1548
+ if categoryOptions.contains("AllowAirPlay") {
1549
+ options.insert(.allowAirPlay)
1550
+ }
1551
+ if categoryOptions.contains("OverrideMutedMicrophone") {
1552
+ if #available(iOS 14.5, *) {
1553
+ options.insert(.overrideMutedMicrophoneInterruption)
1554
+ } else {
1555
+ // Handle the case for earlier versions if needed
1556
+ }
1544
1557
  }
1545
1558
  }
1546
1559
 
@@ -55,13 +55,13 @@ class RNJWPlayerViewController : JWPlayerViewController, JWPlayerViewControllerD
55
55
 
56
56
  override func jwplayer(_ player:JWPlayer, failedWithError code:UInt, message:String) {
57
57
  super.jwplayer(player, failedWithError:code, message:message)
58
- parentView?.onPlayerError?(["error": message])
58
+ parentView?.onPlayerError?(["error": message, "errorCode": code])
59
59
  parentView?.playerFailed = true
60
60
  }
61
61
 
62
62
  override func jwplayer(_ player:JWPlayer, failedWithSetupError code:UInt, message:String) {
63
63
  super.jwplayer(player, failedWithSetupError:code, message:message)
64
- parentView?.onSetupPlayerError?(["error": message])
64
+ parentView?.onSetupPlayerError?(["errorMessage": message, "errorCode": code])
65
65
  parentView?.playerFailed = true
66
66
  }
67
67
 
@@ -78,7 +78,7 @@ class RNJWPlayerViewController : JWPlayerViewController, JWPlayerViewControllerD
78
78
 
79
79
  override func jwplayer(_ player:JWPlayer, encounteredAdWarning code:UInt, message:String) {
80
80
  super.jwplayer(player, encounteredAdWarning:code, message:message)
81
- parentView?.onPlayerAdWarning?(["warning": message])
81
+ parentView?.onPlayerAdWarning?(["warning": message, "code": code])
82
82
  }
83
83
 
84
84
 
@@ -263,11 +263,6 @@ class RNJWPlayerViewController : JWPlayerViewController, JWPlayerViewControllerD
263
263
 
264
264
  // MARK: - JWPlayer State Delegate
265
265
 
266
- override func jwplayerContentIsBuffering(_ player:JWPlayer) {
267
- super.jwplayerContentIsBuffering(player)
268
- parentView?.onBuffer?([:])
269
- }
270
-
271
266
  override func jwplayer(_ player:JWPlayer, isBufferingWithReason reason:JWBufferReason) {
272
267
  super.jwplayer(player, isBufferingWithReason:reason)
273
268
  parentView?.onBuffer?([:])
@@ -280,7 +275,7 @@ class RNJWPlayerViewController : JWPlayerViewController, JWPlayerViewControllerD
280
275
 
281
276
  override func jwplayer(_ player:JWPlayer, didFinishLoadingWithTime loadTime:TimeInterval) {
282
277
  super.jwplayer(player, didFinishLoadingWithTime:loadTime)
283
- parentView?.onLoaded?([:])
278
+ parentView?.onLoaded?(["loadTime":loadTime])
284
279
  }
285
280
 
286
281
  override func jwplayer(_ player:JWPlayer, isAttemptingToPlay playlistItem:JWPlayerItem, reason:JWPlayReason) {
@@ -588,6 +583,7 @@ class RNJWPlayerViewController : JWPlayerViewController, JWPlayerViewControllerD
588
583
 
589
584
  override func jwplayer(_ player:JWPlayer, captionTrackChanged index:Int) {
590
585
  super.jwplayer(player, captionTrackChanged:index)
586
+ parentView.onCaptionsChanged?(["index": index])
591
587
  }
592
588
 
593
589
  override func jwplayer(_ player:JWPlayer, qualityLevelChanged currentLevel:Int) {
@@ -600,6 +596,16 @@ class RNJWPlayerViewController : JWPlayerViewController, JWPlayerViewControllerD
600
596
 
601
597
  override func jwplayer(_ player:JWPlayer, updatedCaptionList options:[JWMediaSelectionOption]) {
602
598
  super.jwplayer(player, updatedCaptionList:options)
599
+
600
+ var tracks: [[String: Any]] = []
601
+ for track in player.captionsTracks {
602
+ var dict: [String: Any] = [:]
603
+ dict["label"] = track.name
604
+ dict["default"] = track.defaultOption
605
+ tracks.append(dict)
606
+ }
607
+ let currentIndex = player.currentCaptionsTrack
608
+ parentView.onCaptionsList?(["index": currentIndex, "tracks": tracks])
603
609
  }
604
610
 
605
611
  override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
@@ -32,6 +32,8 @@ RCT_EXPORT_VIEW_PROPERTY(onPlaylistItem, RCTDirectEventBlock);
32
32
 
33
33
  /* av events */
34
34
  RCT_EXPORT_VIEW_PROPERTY(onAudioTracks, RCTDirectEventBlock);
35
+ RCT_EXPORT_VIEW_PROPERTY(onCaptionsChanged, RCTDirectEventBlock);
36
+ RCT_EXPORT_VIEW_PROPERTY(onCaptionsList, RCTDirectEventBlock);
35
37
 
36
38
  /* player events */
37
39
  RCT_EXPORT_VIEW_PROPERTY(onPlayerReady, RCTDirectEventBlock);
@@ -93,6 +95,8 @@ RCT_EXTERN_METHOD(setVolume: (nonnull NSNumber *)reactTag :(nonnull NSNumber *)v
93
95
 
94
96
  RCT_EXTERN_METHOD(togglePIP: (nonnull NSNumber *)reactTag)
95
97
 
98
+ #if USE_GOOGLE_CAST
99
+
96
100
  RCT_EXTERN_METHOD(setUpCastController: (nonnull NSNumber *)reactTag)
97
101
 
98
102
  RCT_EXTERN_METHOD(presentCastDialog: (nonnull NSNumber *)reactTag)
@@ -103,6 +107,8 @@ RCT_EXTERN_METHOD(availableDevices: (nonnull NSNumber *)reactTag: (RCTPromiseRes
103
107
 
104
108
  RCT_EXTERN_METHOD(castState: (nonnull NSNumber *)reactTag :(RCTPromiseResolveBlock)resolve :(RCTPromiseRejectBlock)reject)
105
109
 
110
+ #endif
111
+
106
112
  RCT_EXTERN_METHOD(getAudioTracks: (nonnull NSNumber *)reactTag: (RCTPromiseResolveBlock)resolve: (RCTPromiseRejectBlock)reject)
107
113
 
108
114
  RCT_EXTERN_METHOD(getCurrentAudioTrack: (nonnull NSNumber *)reactTag :(RCTPromiseResolveBlock)resolve :(RCTPromiseRejectBlock)reject)
@@ -117,7 +123,7 @@ RCT_EXTERN_METHOD(setLockScreenControls: (nonnull NSNumber *)reactTag: (BOOL)sho
117
123
 
118
124
  RCT_EXTERN_METHOD(setCurrentCaptions: (nonnull NSNumber *)reactTag: (nonnull NSNumber *)index)
119
125
 
120
- RCT_EXTERN_METHOD(setCurrentCaptions: (nonnull NSNumber *)reactTag: (nonnull NSNumber *)index)
126
+ RCT_EXTERN_METHOD(getCurrentCaptions: (nonnull NSNumber *)reactTag :(RCTPromiseResolveBlock)resolve :(RCTPromiseRejectBlock)reject)
121
127
 
122
128
  RCT_EXTERN_METHOD(setLicenseKey: (nonnull NSNumber *)reactTag: (nonnull NSString *)license)
123
129
 
@@ -127,6 +133,8 @@ RCT_EXTERN_METHOD(reset)
127
133
 
128
134
  RCT_EXTERN_METHOD(loadPlaylist: (nonnull NSNumber *)reactTag: (nonnull NSArray *)playlist)
129
135
 
136
+ RCT_EXTERN_METHOD(loadPlaylist: (nonnull NSNumber *)reactTag: (nonnull NSString *)playlist)
137
+
130
138
  RCT_EXTERN_METHOD(setFullscreen: (nonnull NSNumber *)reactTag: (BOOL)fullscreen)
131
139
 
132
140
  @end