@pigeonmal/react-native-video 7.0.0-beta.12 → 7.0.0-beta.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,7 +4,7 @@ Date: 19/12/2025
4
4
  (Only android)
5
5
  Install :
6
6
 
7
- 1. npm install @pigeonmal/react-native-video@beta react-native-nitro-fetch
7
+ 1. npm install @pigeonmal/react-native-video@beta @pigeonmal/react-native-nitro-fetch
8
8
  2. Add this to android/app/settings.gradle
9
9
 
10
10
  ```
@@ -12,8 +12,6 @@ include ':media3-ffmpeg-decoder'
12
12
  project(':media3-ffmpeg-decoder').projectDir = file('../node_modules/@pigeonmal/react-native-video/android/media3-ffmpeg-decoder')
13
13
  ```
14
14
 
15
- 3. create a patch for react-native-nitro-fetch like in the patches/react-native-nitro-fetch@x.patch
16
-
17
15
  ---
18
16
 
19
17
  Features:
@@ -31,6 +29,8 @@ Features:
31
29
  - player.resetForReuse() stop playback and clear tracks
32
30
  - player.progressEventInterval change the progress event interval
33
31
  - bugfix: external subtitles in hls/dash
32
+ - bugfix: add langs to external subs
33
+ - bugfix: onloadstart
34
34
  - nullable video player source : new VideoPlayer(undefined);
35
35
  - TextTrack type replaced to PlayerTrack
36
36
  - removed onTrackChange event
@@ -234,7 +234,7 @@ dependencies {
234
234
  implementation "androidx.media3:media3-session:$media3_version"
235
235
 
236
236
  api project(':media3-ffmpeg-decoder')
237
- implementation project(':react-native-nitro-fetch')
237
+ implementation project(':pigeonmal_react-native-nitro-fetch')
238
238
 
239
239
  if (ExoplayerDependencies.useExoplayerDash) {
240
240
  implementation "androidx.media3:media3-exoplayer-dash:$media3_version"
@@ -60,7 +60,7 @@ fun buildHttpDataSourceFactory(context: Context, source: HybridVideoPlayerSource
60
60
  fun buildCronetHttpDataSourceFactory(source: HybridVideoPlayerSourceSpec): CronetDataSource.Factory {
61
61
  // Get Cronet engine and executor from NitroFetch
62
62
  // used before NitroFetch.ioExecutor , but cause blocking thread
63
- val factory = CronetDataSource.Factory(NitroFetch.getEngine(), Executors.newSingleThreadExecutor())
63
+ val factory = CronetDataSource.Factory(NitroFetch.getEngine(), NitroFetch.ioExecutor)
64
64
  .setConnectionTimeoutMs(10_000)
65
65
  .setReadTimeoutMs(10_000)
66
66
  .setResetTimeoutOnRedirects(true)
@@ -92,6 +92,7 @@ fun getSubtitlesConfiguration(
92
92
  .setSelectionFlags(0) // C.SELECTION_FLAG_DEFAULT
93
93
  .setRoleFlags(C.ROLE_FLAG_SUBTITLE)
94
94
  .setLabel(subtitle.label)
95
+ .setLanguage(subtitle.language)
95
96
  .build()
96
97
  subtitlesConfiguration.add(subtitleConfig)
97
98
  } catch (e: Exception) {
@@ -27,13 +27,9 @@ object TrackUtils {
27
27
  val language = format.language
28
28
  val isSelected = trackGroup.isTrackSelected(trackIndex)
29
29
 
30
- val isExternal = trackId.startsWith("external-") == true
31
-
32
- val finalTrackId = if (isExternal) "external-$globalTrackIndex" else trackId
33
-
34
30
  tracks.add(
35
31
  PlayerTrack(
36
- id = finalTrackId,
32
+ id = trackId,
37
33
  label = label,
38
34
  language = language,
39
35
  selected = isSelected
@@ -74,12 +70,7 @@ object TrackUtils {
74
70
  val currentTrackId = format.id ?: "track-$type-$globalTrackIndex"
75
71
  //val label = format.label ?: "Unknown ${globalTrackIndex + 1}"
76
72
 
77
- val isExternal = currentTrackId.startsWith("external-") == true
78
-
79
- val finalTrackId =
80
- if (isExternal) "external-$globalTrackIndex" else currentTrackId
81
-
82
- if (finalTrackId == id) {
73
+ if (currentTrackId == id) {
83
74
  // Enable this specific track
84
75
  trackSelector.setTrackTypeDisabled(type, false)
85
76
  trackSelector.setOverrideForType(
@@ -169,12 +160,8 @@ object TrackUtils {
169
160
  val label = format.label ?: "Unknown ${globalTrackIndex + 1}"
170
161
  val language = format.language
171
162
 
172
- val isExternal = trackId.startsWith("external-") == true
173
-
174
- val finalTrackId = if (isExternal) "external-$globalTrackIndex" else trackId
175
-
176
163
  return@runOnMainThreadSync PlayerTrack(
177
- id = finalTrackId,
164
+ id = trackId,
178
165
  label = label,
179
166
  language = language,
180
167
  selected = true
@@ -210,8 +197,6 @@ object TrackUtils {
210
197
  val format = trackGroup.getTrackFormat(trackIndex)
211
198
 
212
199
  val rawId = format.id ?: "track-${C.TRACK_TYPE_AUDIO}-$globalAudioIndex"
213
- val isExternal = rawId.startsWith("external-")
214
- val finalId = if (isExternal) "external-$globalAudioIndex" else rawId
215
200
 
216
201
  val label = format.label ?: "Unknown ${globalAudioIndex + 1}"
217
202
  val language = format.language
@@ -219,7 +204,7 @@ object TrackUtils {
219
204
 
220
205
  audioTracks.add(
221
206
  PlayerTrack(
222
- id = finalId,
207
+ id = rawId,
223
208
  label = label,
224
209
  language = language,
225
210
  selected = isSelected
@@ -234,8 +219,6 @@ object TrackUtils {
234
219
  val format = trackGroup.getTrackFormat(trackIndex)
235
220
 
236
221
  val rawId = format.id ?: "track-${C.TRACK_TYPE_TEXT}-$globalTextIndex"
237
- val isExternal = rawId.startsWith("external-")
238
- val finalId = if (isExternal) "external-$globalTextIndex" else rawId
239
222
 
240
223
  val label = format.label ?: "Unknown ${globalTextIndex + 1}"
241
224
  val language = format.language
@@ -243,7 +226,7 @@ object TrackUtils {
243
226
 
244
227
  textTracks.add(
245
228
  PlayerTrack(
246
- id = finalId,
229
+ id = rawId,
247
230
  label = label,
248
231
  language = language,
249
232
  selected = isSelected
@@ -259,8 +242,6 @@ object TrackUtils {
259
242
  val format = trackGroup.getTrackFormat(trackIndex)
260
243
 
261
244
  val rawId = format.id ?: "track-${C.TRACK_TYPE_VIDEO}-$globalVideoIndex"
262
- val isExternal = rawId.startsWith("external-")
263
- val finalId = if (isExternal) "external-$globalVideoIndex" else rawId
264
245
 
265
246
  val label = format.label ?: "Unknown ${globalVideoIndex + 1}"
266
247
  val language = format.language
@@ -273,7 +254,7 @@ object TrackUtils {
273
254
  VideoPlayerTrack(
274
255
  width = width,
275
256
  height = height,
276
- id = finalId,
257
+ id = rawId,
277
258
  label = label,
278
259
  language = language,
279
260
  selected = isSelected
@@ -261,18 +261,27 @@ class HybridVideoPlayer() : HybridVideoPlayerSpec(), AutoCloseable {
261
261
  .setRenderersFactory(renderersFactory!!)
262
262
  .build()
263
263
 
264
+ currentPlayerView?.get()?.player = player
265
+
264
266
  loadedWithSource = true
265
267
 
266
268
  player.addListener(playerListener)
267
269
  player.addAnalyticsListener(analyticsListener)
268
270
 
269
- val startPosition = hybridSource.config.startPosition
271
+ setPlayerMediaSource(hybridSource)
272
+ }
273
+
274
+ fun setPlayerMediaSource(hybridSource: HybridVideoPlayerSource) {
275
+ val startPosition = hybridSource.config.startPosition
270
276
  if (startPosition != null && startPosition > 0L) {
271
277
  player.setMediaSource(hybridSource.mediaSource, startPosition)
272
278
  } else {
273
279
  player.setMediaSource(hybridSource.mediaSource)
274
280
  }
281
+ }
275
282
 
283
+ fun preparePlayer(hybridSource: HybridVideoPlayerSource) {
284
+ player.prepare()
276
285
  // Emit onLoadStart
277
286
  val sourceType = if (hybridSource.uri.startsWith("http")) SourceType.NETWORK else SourceType.LOCAL
278
287
  eventEmitter.onLoadStart(onLoadStartData(sourceType = sourceType, source = hybridSource))
@@ -282,9 +291,10 @@ class HybridVideoPlayer() : HybridVideoPlayerSpec(), AutoCloseable {
282
291
 
283
292
  override fun initialize(): Promise<Unit> {
284
293
  return Promise.async {
294
+ val hybridSource = source as? HybridVideoPlayerSource ?: throw PlayerError.InvalidSource
285
295
  return@async runOnMainThreadSync {
286
296
  initializePlayer()
287
- player.prepare()
297
+ preparePlayer(hybridSource)
288
298
  }
289
299
  }
290
300
  }
@@ -295,7 +305,7 @@ class HybridVideoPlayer() : HybridVideoPlayerSpec(), AutoCloseable {
295
305
  runOnMainThread {
296
306
  if (source.config.initializeOnCreation == true) {
297
307
  initializePlayer()
298
- player.prepare()
308
+ preparePlayer(source)
299
309
  }
300
310
  }
301
311
  }
@@ -343,22 +353,19 @@ class HybridVideoPlayer() : HybridVideoPlayerSpec(), AutoCloseable {
343
353
  initializePlayer()
344
354
  } else {
345
355
  renderersFactory?.setTextOffset((hybridSource.config.initialSubtitleDelay ?: 0L) * 1_000L)
346
- val startPosition = hybridSource.config.startPosition
347
- if (startPosition != null && startPosition > 0L) {
348
- player.setMediaSource(hybridSource.mediaSource, startPosition)
349
- } else {
350
- player.setMediaSource(hybridSource.mediaSource)
351
- }
356
+ setPlayerMediaSource(hybridSource)
352
357
  }
353
358
 
354
359
  // Prepare player
355
- player.prepare()
360
+ preparePlayer(hybridSource)
356
361
  }
357
362
  }
358
363
  }
359
364
 
360
365
  override fun preload(): Promise<Unit> {
361
366
  return Promise.async {
367
+ val hybridSource = source as? HybridVideoPlayerSource ?: throw PlayerError.InvalidSource
368
+
362
369
  runOnMainThreadSync {
363
370
  if (!loadedWithSource) {
364
371
  initializePlayer()
@@ -368,7 +375,7 @@ class HybridVideoPlayer() : HybridVideoPlayerSpec(), AutoCloseable {
368
375
  return@runOnMainThreadSync
369
376
  }
370
377
 
371
- player.prepare()
378
+ preparePlayer(hybridSource)
372
379
  }
373
380
  }
374
381
  }
@@ -492,21 +499,12 @@ class HybridVideoPlayer() : HybridVideoPlayerSpec(), AutoCloseable {
492
499
  eventEmitter.onBuffer(false)
493
500
 
494
501
  val allTracks = TrackUtils.getAllPlayerTracksInternal(player)
495
- val selectedVideo: VideoPlayerTrack? =
496
- allTracks.videos.firstOrNull { it.selected }
497
- ?: player.videoFormat?.let { format ->
498
- VideoPlayerTrack(
499
- width = format.width.toDouble(),
500
- height = format.height.toDouble(),
501
- // We don't care for the true information, we use only width and height
502
- id = "general",
503
- label = "General",
504
- selected = true,
505
- language = null
506
- )
507
- }
508
- val width = selectedVideo?.width ?: 0.0
509
- val height = selectedVideo?.height ?: 0.0
502
+ val (width, height) = player.videoFormat?.let { format ->
503
+ format.width.toDouble() to format.height.toDouble()
504
+ } ?: allTracks.videos.firstOrNull { it.selected }?.let {
505
+ it.width to it.height
506
+ } ?: (0.0 to 0.0)
507
+
510
508
  // val rotationDegrees = selectedVideoTrackFormat?.rotationDegrees ?: generalVideoFormat?.rotationDegrees
511
509
 
512
510
  eventEmitter.onLoad(
@@ -653,10 +651,14 @@ class HybridVideoPlayer() : HybridVideoPlayerSpec(), AutoCloseable {
653
651
 
654
652
  override fun resetForReuse() {
655
653
  runOnMainThread {
656
- if (player.playbackState != Player.STATE_IDLE) {
657
- player.stop()
654
+ if (this.source != null) {
655
+ stopProgressUpdates()
656
+ this.source = null
657
+ if (player.playbackState != Player.STATE_IDLE) {
658
+ player.stop()
659
+ }
660
+ player.clearMediaItems()
658
661
  }
659
- player.clearMediaItems()
660
662
  }
661
663
  }
662
664
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pigeonmal/react-native-video",
3
- "version": "7.0.0-beta.12",
3
+ "version": "7.0.0-beta.15",
4
4
  "description": "<Video /> Component for React Native",
5
5
  "source": "./src/index.tsx",
6
6
  "main": "./lib/commonjs/index.js",
@@ -94,7 +94,7 @@
94
94
  "react": "*",
95
95
  "react-native": "*",
96
96
  "react-native-nitro-modules": ">=0.27.2",
97
- "react-native-nitro-fetch": ">=0.1.6"
97
+ "@pigeonmal/react-native-nitro-fetch": ">=0.1.7"
98
98
  },
99
99
  "release-it": {
100
100
  "npm": {