react-native-theoplayer 2.3.0 → 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/android/src/main/java/com/theoplayer/player/PlayerModule.kt +12 -0
  3. package/android/src/main/java/com/theoplayer/presentation/PipUtils.kt +5 -1
  4. package/android/src/main/java/com/theoplayer/track/TrackListAdapter.kt +3 -2
  5. package/android/src/main/java/com/theoplayer/util/TypeUtils.kt +6 -6
  6. package/ios/THEOplayerRCTBridge.m +3 -0
  7. package/ios/THEOplayerRCTMainEventHandler.swift +16 -13
  8. package/ios/THEOplayerRCTPlayerAPI.swift +15 -0
  9. package/ios/THEOplayerRCTTrackMetadataAggregator.swift +2 -2
  10. package/ios/THEOplayerRCTTypeUtils.swift +26 -0
  11. package/ios/THEOplayerRCTView.swift +3 -1
  12. package/ios/backgroundAudio/THEOplayerRCTNowPlayingManager.swift +7 -5
  13. package/ios/backgroundAudio/THEOplayerRCTView+BackgroundAudioConfig.swift +12 -0
  14. package/lib/commonjs/api/player/THEOplayer.js +18 -0
  15. package/lib/commonjs/api/player/THEOplayer.js.map +1 -1
  16. package/lib/commonjs/api/source/SourceDescription.js.map +1 -1
  17. package/lib/commonjs/internal/THEOplayerView.js +6 -1
  18. package/lib/commonjs/internal/THEOplayerView.js.map +1 -1
  19. package/lib/commonjs/internal/THEOplayerView.web.js +7 -7
  20. package/lib/commonjs/internal/THEOplayerView.web.js.map +1 -1
  21. package/lib/commonjs/internal/adapter/NativePlayerState.js.map +1 -1
  22. package/lib/commonjs/internal/adapter/THEOplayerAdapter.js +9 -1
  23. package/lib/commonjs/internal/adapter/THEOplayerAdapter.js.map +1 -1
  24. package/lib/commonjs/internal/adapter/THEOplayerWebAdapter.js +7 -1
  25. package/lib/commonjs/internal/adapter/THEOplayerWebAdapter.js.map +1 -1
  26. package/lib/commonjs/internal/adapter/web/TrackUtils.js +3 -2
  27. package/lib/commonjs/internal/adapter/web/TrackUtils.js.map +1 -1
  28. package/lib/commonjs/internal/adapter/web/WebMediaSession.js +17 -29
  29. package/lib/commonjs/internal/adapter/web/WebMediaSession.js.map +1 -1
  30. package/lib/commonjs/internal/adapter/web/WebPresentationModeManager.js +1 -1
  31. package/lib/commonjs/internal/adapter/web/WebPresentationModeManager.js.map +1 -1
  32. package/lib/module/api/player/THEOplayer.js +16 -1
  33. package/lib/module/api/player/THEOplayer.js.map +1 -1
  34. package/lib/module/api/source/SourceDescription.js.map +1 -1
  35. package/lib/module/internal/THEOplayerView.js +6 -1
  36. package/lib/module/internal/THEOplayerView.js.map +1 -1
  37. package/lib/module/internal/THEOplayerView.web.js +7 -7
  38. package/lib/module/internal/THEOplayerView.web.js.map +1 -1
  39. package/lib/module/internal/adapter/NativePlayerState.js.map +1 -1
  40. package/lib/module/internal/adapter/THEOplayerAdapter.js +10 -2
  41. package/lib/module/internal/adapter/THEOplayerAdapter.js.map +1 -1
  42. package/lib/module/internal/adapter/THEOplayerWebAdapter.js +7 -1
  43. package/lib/module/internal/adapter/THEOplayerWebAdapter.js.map +1 -1
  44. package/lib/module/internal/adapter/web/TrackUtils.js +3 -2
  45. package/lib/module/internal/adapter/web/TrackUtils.js.map +1 -1
  46. package/lib/module/internal/adapter/web/WebMediaSession.js +15 -29
  47. package/lib/module/internal/adapter/web/WebMediaSession.js.map +1 -1
  48. package/lib/module/internal/adapter/web/WebPresentationModeManager.js +1 -1
  49. package/lib/module/internal/adapter/web/WebPresentationModeManager.js.map +1 -1
  50. package/lib/typescript/api/player/THEOplayer.d.ts +22 -0
  51. package/lib/typescript/api/source/SourceDescription.d.ts +6 -0
  52. package/lib/typescript/internal/adapter/NativePlayerState.d.ts +2 -0
  53. package/lib/typescript/internal/adapter/THEOplayerAdapter.d.ts +3 -1
  54. package/lib/typescript/internal/adapter/THEOplayerWebAdapter.d.ts +4 -2
  55. package/lib/typescript/internal/adapter/web/WebMediaSession.d.ts +2 -1
  56. package/package.json +9 -4
  57. package/src/api/player/THEOplayer.ts +24 -0
  58. package/src/api/source/SourceDescription.ts +8 -0
  59. package/src/internal/THEOplayerView.tsx +6 -1
  60. package/src/internal/THEOplayerView.web.tsx +4 -7
  61. package/src/internal/adapter/NativePlayerState.ts +2 -0
  62. package/src/internal/adapter/THEOplayerAdapter.ts +12 -1
  63. package/src/internal/adapter/THEOplayerWebAdapter.ts +10 -2
  64. package/src/internal/adapter/web/TrackUtils.ts +3 -2
  65. package/src/internal/adapter/web/WebMediaSession.ts +14 -29
  66. package/src/internal/adapter/web/WebPresentationModeManager.ts +1 -1
@@ -1,10 +1,10 @@
1
1
  import { DefaultEventDispatcher } from './event/DefaultEventDispatcher';
2
- import type { AdsAPI, CastAPI, MediaTrack, NativeHandleType, PlayerEventMap, PreloadType, TextTrack, TextTrackStyle, THEOplayer, PlayerConfiguration } from 'react-native-theoplayer';
2
+ import type { AdsAPI, CastAPI, MediaTrack, NativeHandleType, PlayerConfiguration, PlayerEventMap, PreloadType, TextTrack, TextTrackStyle, THEOplayer } from 'react-native-theoplayer';
3
+ import { AspectRatio, PresentationMode } from 'react-native-theoplayer';
3
4
  import type * as THEOplayerWeb from 'theoplayer';
4
5
  import type { ABRConfiguration, SourceDescription } from 'src/api/barrel';
5
6
  import type { PiPConfiguration } from 'src/api/pip/PiPConfiguration';
6
7
  import type { BackgroundAudioConfiguration } from 'src/api/backgroundAudio/BackgroundAudioConfiguration';
7
- import { PresentationMode } from 'react-native-theoplayer';
8
8
  export declare class THEOplayerWebAdapter extends DefaultEventDispatcher<PlayerEventMap> implements THEOplayer {
9
9
  private readonly _player;
10
10
  private readonly _adsAdapter;
@@ -61,6 +61,8 @@ export declare class THEOplayerWebAdapter extends DefaultEventDispatcher<PlayerE
61
61
  set targetVideoQuality(targetVideoQuality: number | number[] | undefined);
62
62
  get currentTime(): number;
63
63
  set currentTime(currentTime: number);
64
+ get aspectRatio(): AspectRatio;
65
+ set aspectRatio(_ratio: AspectRatio);
64
66
  get duration(): number;
65
67
  get ads(): AdsAPI;
66
68
  get cast(): CastAPI;
@@ -25,9 +25,10 @@ export declare class WebMediaSession {
25
25
  private onAdbreakBegin;
26
26
  private onAdbreakEnd;
27
27
  private isLive;
28
- private isAd;
28
+ private isInAd;
29
29
  private isInBackground;
30
30
  private isTrickplayEnabled;
31
31
  private isPlayPauseEnabled;
32
+ private isBackgroundAudioEnabled;
32
33
  }
33
34
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-theoplayer",
3
- "version": "2.3.0",
3
+ "version": "2.5.0",
4
4
  "description": "A THEOplayer video component for react-native.",
5
5
  "main": "lib/commonjs/index",
6
6
  "module": "lib/module/index",
@@ -25,7 +25,7 @@
25
25
  "scripts": {
26
26
  "typescript": "tsc --noEmit",
27
27
  "lint": "eslint \"**/*.{ts,tsx}\"",
28
- "prepare": "bob build",
28
+ "prepare": "bob build && husky install",
29
29
  "release": "release-it",
30
30
  "pods": "cd example && pod-install --quiet"
31
31
  },
@@ -67,7 +67,13 @@
67
67
  },
68
68
  "peerDependencies": {
69
69
  "react": "*",
70
- "react-native": "*"
70
+ "react-native": "*",
71
+ "theoplayer": ">=5.0.1"
72
+ },
73
+ "peerDependenciesMeta": {
74
+ "theoplayer": {
75
+ "optional": true
76
+ }
71
77
  },
72
78
  "commitlint": {
73
79
  "extends": [
@@ -116,7 +122,6 @@
116
122
  "react-native-svg": "^13.8.0",
117
123
  "react-native-svg-web": "^1.0.0",
118
124
  "react-native-url-polyfill": "^1.3.0",
119
- "theoplayer": ">=5.0.1",
120
125
  "url-polyfill": "^1.1.12"
121
126
  }
122
127
  }
@@ -14,6 +14,22 @@ import type { BackgroundAudioConfiguration } from '../backgroundAudio/Background
14
14
 
15
15
  export type PreloadType = 'none' | 'metadata' | 'auto' | '';
16
16
 
17
+ /**
18
+ * Specifies an aspect ratio for the player.
19
+ *
20
+ * <br/> - `FIT` (default): Scales the player so that all content fits inside its bounding box, keeping the original aspect ratio of the content..
21
+ * <br/> - `FILL`: Scales the player so that all content fits inside the bounding box, which will be stretched to fill it entirely.
22
+ * <br/> - `ASPECT_FILL`: Scales the player so that the content fills up the entire bounding box, keeping the original aspect ratio of the content.
23
+ *
24
+ * @public
25
+ * @defaultValue `'FIT'`
26
+ */
27
+ export enum AspectRatio {
28
+ FIT = 'fit',
29
+ FILL = 'fill',
30
+ ASPECT_FILL = 'aspectFill',
31
+ }
32
+
17
33
  export type NativeHandleType = unknown;
18
34
 
19
35
  /**
@@ -153,6 +169,14 @@ export interface THEOplayer extends EventDispatcher<PlayerEventMap> {
153
169
  */
154
170
  currentTime: number;
155
171
 
172
+ /**
173
+ * Used to set the aspect ratio of the player.
174
+ *
175
+ * @remarks
176
+ * Only available for iOS and Android.
177
+ */
178
+ aspectRatio: AspectRatio;
179
+
156
180
  /**
157
181
  * The active configuration for PiP.
158
182
  */
@@ -223,6 +223,14 @@ export interface TextTrackDescription {
223
223
  * @public
224
224
  */
225
225
  export interface BaseSource {
226
+
227
+ /**
228
+ * The cross-origin setting of the source.
229
+ *
230
+ * @defaultValue `''`
231
+ */
232
+ crossOrigin?: CrossOriginSetting;
233
+
226
234
  /**
227
235
  * The URL of a time server used by the player to synchronise the time in DASH sources.
228
236
  *
@@ -254,7 +254,12 @@ export class THEOplayerView extends PureComponent<React.PropsWithChildren<THEOpl
254
254
 
255
255
  private _onTextTrackEvent = (event: NativeSyntheticEvent<NativeTextTrackEvent>) => {
256
256
  const nativeEvent = event.nativeEvent;
257
- this._facade.dispatchEvent(new DefaultTextTrackEvent(toTextTrackEventType(nativeEvent.type), nativeEvent.trackUid, nativeEvent.cue));
257
+ const cue = nativeEvent.cue;
258
+ if (cue) {
259
+ cue.startTime = decodeNanInf(cue.startTime);
260
+ cue.endTime = decodeNanInf(cue.endTime);
261
+ }
262
+ this._facade.dispatchEvent(new DefaultTextTrackEvent(toTextTrackEventType(nativeEvent.type), nativeEvent.trackUid, cue));
258
263
  };
259
264
 
260
265
  private _onMediaTrackListEvent = (event: NativeSyntheticEvent<NativeMediaTrackListEvent>) => {
@@ -15,21 +15,18 @@ export function THEOplayerView(props: React.PropsWithChildren<THEOplayerViewProp
15
15
  // Create player inside container.
16
16
  if (container.current) {
17
17
  const chromeless = config?.chromeless === true || config?.chromeless === undefined;
18
+ const updatedConfig = {...config, allowNativeFullscreen: true};
18
19
  if (chromeless) {
19
- player.current = new THEOplayer.ChromelessPlayer(container.current, config);
20
+ player.current = new THEOplayer.ChromelessPlayer(container.current, updatedConfig);
20
21
  } else {
21
22
  player.current = new THEOplayer.Player(container.current, {
22
- ...config,
23
+ ...updatedConfig,
23
24
  ui: {
24
25
  fluid: true,
25
- },
26
- allowNativeFullscreen: true,
26
+ }
27
27
  } as THEOplayer.PlayerConfiguration);
28
28
  }
29
29
 
30
- // Prepare the player to ChromelessPlayer.autoplay on platforms where autoplay is restricted without user action.
31
- player.current.prepareWithUserAction();
32
-
33
30
  // Adapt native player to react-native player.
34
31
  adapter.current = new THEOplayerWebAdapter(player.current, config);
35
32
 
@@ -1,6 +1,7 @@
1
1
  import type { MediaTrack, PreloadType, PresentationMode, SourceDescription, TextTrack, TimeRange } from 'react-native-theoplayer';
2
2
  import type { BackgroundAudioConfiguration } from '../../api/backgroundAudio/BackgroundAudioConfiguration';
3
3
  import type { PiPConfiguration } from 'react-native-theoplayer';
4
+ import type { AspectRatio } from 'react-native-theoplayer';
4
5
 
5
6
  export interface NativePlayerState {
6
7
  source: SourceDescription | undefined;
@@ -18,6 +19,7 @@ export interface NativePlayerState {
18
19
  duration: number;
19
20
  playbackRate: number;
20
21
  preload: PreloadType;
22
+ aspectRatio: AspectRatio;
21
23
  audioTracks: MediaTrack[];
22
24
  videoTracks: MediaTrack[];
23
25
  textTracks: TextTrack[];
@@ -23,6 +23,7 @@ import type {
23
23
  } from 'react-native-theoplayer';
24
24
  import {
25
25
  addTrack,
26
+ AspectRatio,
26
27
  findMediaTrackByUid,
27
28
  MediaTrackEventType,
28
29
  MediaTrackType,
@@ -58,6 +59,7 @@ const defaultPlayerState: NativePlayerState = {
58
59
  duration: NaN,
59
60
  playbackRate: 1,
60
61
  preload: 'none',
62
+ aspectRatio: AspectRatio.FIT,
61
63
  audioTracks: [],
62
64
  videoTracks: [],
63
65
  textTracks: [],
@@ -372,7 +374,7 @@ export class THEOplayerAdapter extends DefaultEventDispatcher<PlayerEventMap> im
372
374
  set selectedTextTrack(trackUid: number | undefined) {
373
375
  this._state.selectedTextTrack = trackUid;
374
376
  this.textTracks.forEach((track) => {
375
- if (track.uid == trackUid) {
377
+ if (track.uid === trackUid) {
376
378
  track.mode = TextTrackMode.showing;
377
379
  } else if (track.mode === TextTrackMode.showing) {
378
380
  track.mode = TextTrackMode.disabled;
@@ -435,6 +437,15 @@ export class THEOplayerAdapter extends DefaultEventDispatcher<PlayerEventMap> im
435
437
  NativeModules.PlayerModule.setVolume(this._view.nativeHandle, volume);
436
438
  }
437
439
 
440
+ get aspectRatio(): AspectRatio {
441
+ return this._state.aspectRatio;
442
+ }
443
+
444
+ set aspectRatio(ratio: AspectRatio) {
445
+ this._state.aspectRatio = ratio;
446
+ NativeModules.PlayerModule.setAspectRatio(this._view.nativeHandle, ratio);
447
+ }
448
+
438
449
  pause(): void {
439
450
  this._state.paused = true;
440
451
  NativeModules.PlayerModule.setPaused(this._view.nativeHandle, true);
@@ -4,13 +4,14 @@ import type {
4
4
  CastAPI,
5
5
  MediaTrack,
6
6
  NativeHandleType,
7
+ PlayerConfiguration,
7
8
  PlayerEventMap,
8
9
  PreloadType,
9
10
  TextTrack,
10
11
  TextTrackStyle,
11
12
  THEOplayer,
12
- PlayerConfiguration,
13
13
  } from 'react-native-theoplayer';
14
+ import { AspectRatio, PresentationMode } from 'react-native-theoplayer';
14
15
  import { THEOplayerWebAdsAdapter } from './ads/THEOplayerWebAdsAdapter';
15
16
  import { THEOplayerWebCastAdapter } from './cast/THEOplayerWebCastAdapter';
16
17
  import type * as THEOplayerWeb from 'theoplayer';
@@ -22,7 +23,6 @@ import type { PiPConfiguration } from 'src/api/pip/PiPConfiguration';
22
23
  import type { BackgroundAudioConfiguration } from 'src/api/backgroundAudio/BackgroundAudioConfiguration';
23
24
  import { WebPresentationModeManager } from './web/WebPresentationModeManager';
24
25
  import { WebMediaSession } from './web/WebMediaSession';
25
- import { PresentationMode } from 'react-native-theoplayer';
26
26
 
27
27
  const defaultBackgroundAudioConfiguration: BackgroundAudioConfiguration = {
28
28
  enabled: false,
@@ -240,6 +240,14 @@ export class THEOplayerWebAdapter extends DefaultEventDispatcher<PlayerEventMap>
240
240
  }
241
241
  }
242
242
 
243
+ get aspectRatio(): AspectRatio {
244
+ return AspectRatio.FIT;
245
+ }
246
+
247
+ set aspectRatio(_ratio: AspectRatio) {
248
+ // unused
249
+ }
250
+
243
251
  get duration(): number {
244
252
  return this._player.duration * 1e3;
245
253
  }
@@ -7,13 +7,14 @@ import type {
7
7
  TextTracksList as NativeTextTrackList,
8
8
  } from 'theoplayer';
9
9
  import type { MediaTrack, TextTrack, TextTrackCue } from 'react-native-theoplayer';
10
+ import { decodeNanInf } from '../../utils/TypeUtils';
10
11
 
11
12
  export function fromNativeCue(cue: NativeTextTrackCue): TextTrackCue {
12
13
  return {
13
14
  id: cue.id,
14
15
  uid: cue.uid,
15
- startTime: 1e3 * cue.startTime,
16
- endTime: 1e3 * cue.endTime,
16
+ startTime: decodeNanInf(1e3 * cue.startTime),
17
+ endTime: decodeNanInf(1e3 * cue.endTime),
17
18
  content: cue.content,
18
19
  } as TextTrackCue;
19
20
  }
@@ -1,7 +1,6 @@
1
1
  /* eslint-disable @typescript-eslint/no-empty-function */
2
2
  import type { ChromelessPlayer } from 'theoplayer';
3
3
  import type { THEOplayerWebAdapter } from '../THEOplayerWebAdapter';
4
- import { PresentationMode } from 'react-native-theoplayer';
5
4
 
6
5
  interface WebMediaSessionConfig {
7
6
  skipTime: number;
@@ -151,43 +150,29 @@ export class WebMediaSession {
151
150
  return !isFinite(this._player.duration);
152
151
  }
153
152
 
154
- private isAd(): boolean {
155
- return this._player.ads?.playing == true;
153
+ private isInAd(): boolean {
154
+ return this._player.ads?.playing === true;
156
155
  }
157
156
 
158
157
  private isInBackground(): boolean {
159
158
  return document.visibilityState !== 'visible';
160
159
  }
161
160
 
161
+ // By default, only show trick-play buttons if:
162
+ // - backgroundAudio is enabled, or the player is in foreground;
163
+ // - and, the current asset is neither a live stream, nor an ad.
162
164
  private isTrickplayEnabled(): boolean {
163
- // By default, no trickplay for live
164
- if (this.isLive()) {
165
- return false;
166
- }
167
-
168
- // In PiP mode, disable trick-play for ads.
169
- if (this._webAdapter.presentationMode === PresentationMode.pip) {
170
- return !this.isAd();
171
- }
172
- // During background playback
173
- if (this.isInBackground()) {
174
- // Disable trick-play for ads.
175
- return !(this.isAd() || this.isLive());
176
- }
177
- return true;
165
+ return (this.isBackgroundAudioEnabled() || !this.isInBackground()) && !this.isLive() && !this.isInAd();
178
166
  }
179
167
 
168
+ // By default, only show a play/pause button if:
169
+ // - backgroundAudio is enabled, or the player is in foreground;
170
+ // - and, the current asset is not an ad.
180
171
  private isPlayPauseEnabled(): boolean {
181
- // In PiP mode
182
- if (this._webAdapter.presentationMode === PresentationMode.pip) {
183
- // Disable play/pause for ads
184
- return !this.isAd();
185
- }
186
- // During background playback
187
- if (this.isInBackground()) {
188
- // Disable play/pause for ads & live content.
189
- return !(this.isAd() || this.isLive());
190
- }
191
- return true;
172
+ return (this.isBackgroundAudioEnabled() || !this.isInBackground()) && !this.isInAd();
173
+ }
174
+
175
+ private isBackgroundAudioEnabled(): boolean {
176
+ return this._webAdapter.backgroundAudioConfiguration.enabled === true;
192
177
  }
193
178
  }
@@ -63,7 +63,7 @@ export class WebPresentationModeManager {
63
63
  }
64
64
  }
65
65
  // listen for pip updates on element
66
- if (this._element != null) {
66
+ if (this._element !== undefined) {
67
67
  this._element.onenterpictureinpicture = () => {
68
68
  this.updatePresentationMode();
69
69
  };