@cinecrew/cinecrew-player 0.1.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 (66) hide show
  1. package/CineCrewPlayer.podspec +22 -0
  2. package/LICENSE +21 -0
  3. package/NOTICE +6 -0
  4. package/README.md +574 -0
  5. package/android/build.gradle +48 -0
  6. package/android/proguard-rules.pro +29 -0
  7. package/android/src/main/AndroidManifest.xml +2 -0
  8. package/android/src/main/java/com/yuanzhou/vlc/ReactVlcPlayerPackage.java +28 -0
  9. package/android/src/main/java/com/yuanzhou/vlc/vlcplayer/ReactVlcPlayerView.java +988 -0
  10. package/android/src/main/java/com/yuanzhou/vlc/vlcplayer/ReactVlcPlayerViewManager.java +208 -0
  11. package/android/src/main/java/com/yuanzhou/vlc/vlcplayer/VideoEventEmitter.java +136 -0
  12. package/android/src/main/res/values/strings.xml +3 -0
  13. package/app.plugin.cjs +1 -0
  14. package/assets/cinecrew-player-logo.svg +44 -0
  15. package/package.json +132 -0
  16. package/packages/react-native-vlc-media-player/LICENSE +21 -0
  17. package/packages/react-native-vlc-media-player/VLCPlayer.js +207 -0
  18. package/packages/react-native-vlc-media-player/expo/android/withGradleTasks.cjs +49 -0
  19. package/packages/react-native-vlc-media-player/expo/ios/withMobileVlcKit.cjs +28 -0
  20. package/packages/react-native-vlc-media-player/expo/withVlcMediaPlayer.cjs +10 -0
  21. package/packages/react-native-vlc-media-player/index.d.ts +354 -0
  22. package/packages/react-native-vlc-media-player/ios/RCTVLCPlayer/RCTVLCPlayer.h +36 -0
  23. package/packages/react-native-vlc-media-player/ios/RCTVLCPlayer/RCTVLCPlayer.m +635 -0
  24. package/packages/react-native-vlc-media-player/ios/RCTVLCPlayer/RCTVLCPlayerManager.h +5 -0
  25. package/packages/react-native-vlc-media-player/ios/RCTVLCPlayer/RCTVLCPlayerManager.m +100 -0
  26. package/src/native/InlineLivePlayer.js +321 -0
  27. package/src/native/MediaPlayerView.js +3093 -0
  28. package/src/native/customization.js +44 -0
  29. package/src/native/index.js +107 -0
  30. package/src/native/media/ElectronVideoPlayer.js +288 -0
  31. package/src/native/media/EmojiPickerModal.js +30 -0
  32. package/src/native/media/LiveChatDrawer.js +1177 -0
  33. package/src/native/media/LiveRecordingOverlay.js +319 -0
  34. package/src/native/media/WebVideoPlayer.js +320 -0
  35. package/src/native/media/YouTubeVideoPlayer.native.js +120 -0
  36. package/src/native/media/YouTubeVideoPlayer.web.js +169 -0
  37. package/src/native/media/player/AudioOnlyView.js +337 -0
  38. package/src/native/media/player/CenterControls.js +94 -0
  39. package/src/native/media/player/ExoVideoFallback.js +329 -0
  40. package/src/native/media/player/PipOverlay.js +1 -0
  41. package/src/native/media/player/PlayerBottomBar.js +295 -0
  42. package/src/native/media/player/PlayerTopBar.js +255 -0
  43. package/src/native/media/player/VLCBoundary.js +41 -0
  44. package/src/native/media/player/VerticalIndicator.js +184 -0
  45. package/src/native/media/player/index.js +9 -0
  46. package/src/native/media/player/playerConstants.js +159 -0
  47. package/src/native/media/web/useWebAc3AudioPlayback.native.js +6 -0
  48. package/src/native/media/web/useWebAc3AudioPlayback.web.js +219 -0
  49. package/src/native/media/web/useWebHlsPlayback.native.js +3 -0
  50. package/src/native/media/web/useWebHlsPlayback.web.js +66 -0
  51. package/src/native/media/web/useWebMediaSession.js +90 -0
  52. package/src/native/media/web/useWebMpegTsPlayback.native.js +3 -0
  53. package/src/native/media/web/useWebMpegTsPlayback.web.js +356 -0
  54. package/src/native/media/web/useWebVideoAspectRatio.js +52 -0
  55. package/src/native/media/web/webPlaybackErrors.js +4 -0
  56. package/src/utils/layoutUtils.js +12 -0
  57. package/src/utils/mediaUtils.js +7 -0
  58. package/src/utils/recording.js +8 -0
  59. package/src/utils/runtimePlatform.js +19 -0
  60. package/src/utils/sourceUtils.js +99 -0
  61. package/src/utils/youtubeHtml.js +34 -0
  62. package/src/web/index.js +1129 -0
  63. package/src/web/styles.css +378 -0
  64. package/types/index.d.ts +268 -0
  65. package/vendor/mpegts.js/LICENSE +202 -0
  66. package/vendor/mpegts.js/mpegts.js +3 -0
@@ -0,0 +1,635 @@
1
+ #import "React/RCTConvert.h"
2
+ #import "RCTVLCPlayer.h"
3
+ #import "React/RCTBridgeModule.h"
4
+ #import "React/RCTEventDispatcher.h"
5
+ #import "React/UIView+React.h"
6
+ #if TARGET_OS_TV
7
+ #import <TVVLCKit/TVVLCKit.h>
8
+ #else
9
+ #import <MobileVLCKit/MobileVLCKit.h>
10
+ #endif
11
+ #import <AVFoundation/AVFoundation.h>
12
+ static NSString *const statusKeyPath = @"status";
13
+ static NSString *const playbackLikelyToKeepUpKeyPath = @"playbackLikelyToKeepUp";
14
+ static NSString *const playbackBufferEmptyKeyPath = @"playbackBufferEmpty";
15
+ static NSString *const readyForDisplayKeyPath = @"readyForDisplay";
16
+ static NSString *const playbackRate = @"rate";
17
+
18
+
19
+ #if !defined(DEBUG) || !(TARGET_IPHONE_SIMULATOR)
20
+ #define NSLog(...)
21
+ #endif
22
+
23
+
24
+ @implementation RCTVLCPlayer
25
+ {
26
+
27
+ /* Required to publish events */
28
+ RCTEventDispatcher *_eventDispatcher;
29
+ VLCMediaPlayer *_player;
30
+
31
+ NSDictionary * _videoInfo;
32
+ NSString * _subtitleUri;
33
+
34
+ BOOL _paused;
35
+ BOOL _autoplay;
36
+ BOOL _acceptInvalidCertificates;
37
+ BOOL _playInBackground;
38
+ BOOL _playWhenInactive;
39
+ NSString *_sourceURI;
40
+ }
41
+
42
+ - (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher
43
+ {
44
+ if ((self = [super init])) {
45
+ _eventDispatcher = eventDispatcher;
46
+
47
+ [[NSNotificationCenter defaultCenter] addObserver:self
48
+ selector:@selector(applicationWillResignActive:)
49
+ name:UIApplicationWillResignActiveNotification
50
+ object:nil];
51
+
52
+ [[NSNotificationCenter defaultCenter] addObserver:self
53
+ selector:@selector(applicationDidEnterBackground:)
54
+ name:UIApplicationDidEnterBackgroundNotification
55
+ object:nil];
56
+
57
+ [[NSNotificationCenter defaultCenter] addObserver:self
58
+ selector:@selector(applicationWillEnterForeground:)
59
+ name:UIApplicationWillEnterForegroundNotification
60
+ object:nil];
61
+
62
+ [[NSNotificationCenter defaultCenter] addObserver:self
63
+ selector:@selector(applicationDidBecomeActive:)
64
+ name:UIApplicationDidBecomeActiveNotification
65
+ object:nil];
66
+
67
+ }
68
+
69
+ return self;
70
+ }
71
+
72
+ - (void)applicationDidEnterBackground:(NSNotification *)notification
73
+ {
74
+ if (!_paused && (_playInBackground || _playWhenInactive)) {
75
+ if (_player) {
76
+ _player.drawable = nil;
77
+ }
78
+ [self configureAudioSession];
79
+ [self play];
80
+ }
81
+ }
82
+
83
+ - (void)applicationWillResignActive:(NSNotification *)notification
84
+ {
85
+ if (!_paused && (_playInBackground || _playWhenInactive)) {
86
+ if (_player) {
87
+ _player.drawable = nil;
88
+ }
89
+ [self configureAudioSession];
90
+ [self play];
91
+ }
92
+ }
93
+
94
+ - (void)applicationWillEnterForeground:(NSNotification *)notification
95
+ {
96
+ if (_player && _player.drawable != self) {
97
+ _player.drawable = self;
98
+ }
99
+ [self configureAudioSession];
100
+ if (!_paused && (_playInBackground || _playWhenInactive)) {
101
+ [self play];
102
+ }
103
+ }
104
+
105
+ - (void)applicationDidBecomeActive:(NSNotification *)notification
106
+ {
107
+ if (_player && _player.drawable != self) {
108
+ _player.drawable = self;
109
+ }
110
+ if (!_paused && (_playInBackground || _playWhenInactive)) {
111
+ [self play];
112
+ }
113
+ }
114
+
115
+ - (void)play
116
+ {
117
+ if (_player) {
118
+ [_player play];
119
+ _paused = NO;
120
+ if (_playInBackground || _playWhenInactive) {
121
+ [self configureAudioSession];
122
+ }
123
+ }
124
+ }
125
+
126
+ - (void)pause
127
+ {
128
+ if (_player) {
129
+ [_player pause];
130
+ _paused = YES;
131
+ }
132
+ }
133
+
134
+ - (void)configureAudioSession
135
+ {
136
+ #if !TARGET_OS_TV
137
+ AVAudioSession *session = [AVAudioSession sharedInstance];
138
+ NSError *error = nil;
139
+ if (_playInBackground || _playWhenInactive) {
140
+ [session setCategory:AVAudioSessionCategoryPlayback
141
+ mode:AVAudioSessionModeDefault
142
+ options:AVAudioSessionCategoryOptionAllowBluetooth | AVAudioSessionCategoryOptionAllowAirPlay
143
+ error:&error];
144
+ [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
145
+ } else {
146
+ [session setCategory:AVAudioSessionCategoryPlayback
147
+ mode:AVAudioSessionModeMoviePlayback
148
+ options:AVAudioSessionCategoryOptionAllowBluetooth | AVAudioSessionCategoryOptionAllowAirPlay
149
+ error:&error];
150
+ }
151
+ [session setActive:YES error:&error];
152
+ #endif
153
+ }
154
+
155
+ - (void)setSource:(NSDictionary *)source
156
+ {
157
+ NSString* uriString = [source objectForKey:@"uri"];
158
+ if (_player && uriString.length > 0 && [_sourceURI isEqualToString:uriString]) {
159
+ // React Native can resend an equivalent source dictionary whenever a
160
+ // control prop changes. Keep the existing media item and its position.
161
+ return;
162
+ }
163
+
164
+ if (_player) {
165
+ [self _release];
166
+ }
167
+
168
+ _videoInfo = nil;
169
+
170
+ // [bavv edit start]
171
+ _sourceURI = [uriString copy];
172
+ NSURL* uri = [NSURL URLWithString:uriString];
173
+ int initType = [source objectForKey:@"initType"];
174
+ NSDictionary* initOptions = [source objectForKey:@"initOptions"];
175
+
176
+ // Get acceptInvalidCertificates from source
177
+ _acceptInvalidCertificates = [[source objectForKey:@"acceptInvalidCertificates"] boolValue];
178
+ NSLog(@"iOS: Set acceptInvalidCertificates to %@", _acceptInvalidCertificates ? @"YES" : @"NO");
179
+
180
+ if (initType == 1) {
181
+ _player = [[VLCMediaPlayer alloc] init];
182
+ } else {
183
+ _player = [[VLCMediaPlayer alloc] initWithOptions:initOptions];
184
+ }
185
+ _player.delegate = self;
186
+ _player.drawable = self;
187
+ // [bavv edit end]
188
+
189
+ VLCLibrary *library = _player.libraryInstance;
190
+
191
+ VLCConsoleLogger *consoleLogger = [[VLCConsoleLogger alloc] init];
192
+ consoleLogger.level = kVLCLogLevelDebug;
193
+ library.loggers = @[consoleLogger];
194
+
195
+ // Create dialog provider with custom UI to handle dialogs programmatically
196
+ self.dialogProvider = [[VLCDialogProvider alloc] initWithLibrary:library customUI:YES];
197
+ self.dialogProvider.customRenderer = self;
198
+ _player.media = [VLCMedia mediaWithURL:uri];
199
+
200
+ if (_autoplay)
201
+ [_player play];
202
+
203
+ [self configureAudioSession];
204
+ }
205
+
206
+ - (void)setPlayInBackground:(BOOL)value
207
+ {
208
+ _playInBackground = value;
209
+ if (value) [self configureAudioSession];
210
+ }
211
+
212
+ - (void)setPlayWhenInactive:(BOOL)value
213
+ {
214
+ _playWhenInactive = value;
215
+ if (value) [self configureAudioSession];
216
+ }
217
+
218
+ - (void)setAutoplay:(BOOL)autoplay
219
+ {
220
+ _autoplay = autoplay;
221
+
222
+ if (autoplay)
223
+ [self play];
224
+ }
225
+
226
+ - (void)setPaused:(BOOL)paused
227
+ {
228
+ _paused = paused;
229
+
230
+ if (!paused) {
231
+ [self play];
232
+ } else {
233
+ [self pause];
234
+ }
235
+ }
236
+
237
+ - (void)setResume:(BOOL)resume
238
+ {
239
+ if (resume) {
240
+ [self play];
241
+ } else {
242
+ [self pause];
243
+ }
244
+ }
245
+
246
+ - (void)setSubtitleUri:(NSString *)subtitleUri
247
+ {
248
+ NSURL *url = [NSURL URLWithString:subtitleUri];
249
+
250
+ if (url.absoluteString.length != 0 && _player) {
251
+ _subtitleUri = url;
252
+ [_player addPlaybackSlave:_subtitleUri type:VLCMediaPlaybackSlaveTypeSubtitle enforce:YES];
253
+ } else {
254
+ NSLog(@"Invalid subtitle URI: %@", subtitleUri);
255
+ }
256
+ }
257
+
258
+ // ==== player delegate methods ====
259
+
260
+ - (void)mediaPlayerTimeChanged:(NSNotification *)aNotification
261
+ {
262
+ [self updateVideoProgress];
263
+ }
264
+
265
+ - (void)mediaPlayerStateChanged:(NSNotification *)aNotification
266
+ {
267
+
268
+ NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
269
+ NSLog(@"userInfo %@",[aNotification userInfo]);
270
+ NSLog(@"standardUserDefaults %@",defaults);
271
+ if (_player) {
272
+ VLCMediaPlayerState state = _player.state;
273
+ switch (state) {
274
+ case VLCMediaPlayerStateOpening:
275
+ NSLog(@"VLCMediaPlayerStateOpening %i", _player.numberOfAudioTracks);
276
+ self.onVideoOpen(@{
277
+ @"target": self.reactTag
278
+ });
279
+ self.onVideoLoadStart(@{
280
+ @"target": self.reactTag
281
+ });
282
+ break;
283
+ case VLCMediaPlayerStatePaused:
284
+ _paused = YES;
285
+ NSLog(@"VLCMediaPlayerStatePaused %i", _player.numberOfAudioTracks);
286
+ self.onVideoPaused(@{
287
+ @"target": self.reactTag
288
+ });
289
+ break;
290
+ case VLCMediaPlayerStateStopped:
291
+ NSLog(@"VLCMediaPlayerStateStopped %i", _player.numberOfAudioTracks);
292
+ self.onVideoStopped(@{
293
+ @"target": self.reactTag
294
+ });
295
+ break;
296
+ case VLCMediaPlayerStateBuffering:
297
+ NSLog(@"VLCMediaPlayerStateBuffering %i", _player.numberOfAudioTracks);
298
+ self.onVideoBuffering(@{
299
+ @"target": self.reactTag
300
+ });
301
+ break;
302
+ case VLCMediaPlayerStatePlaying:
303
+ _paused = NO;
304
+ NSLog(@"VLCMediaPlayerStatePlaying %i", _player.numberOfAudioTracks);
305
+ self.onVideoPlaying(@{
306
+ @"target": self.reactTag,
307
+ @"seekable": [NSNumber numberWithBool:[_player isSeekable]],
308
+ @"duration":[NSNumber numberWithInt:[_player.media.length intValue]]
309
+ });
310
+ break;
311
+ case VLCMediaPlayerStateEnded:
312
+ NSLog(@"VLCMediaPlayerStateEnded %i", _player.numberOfAudioTracks);
313
+ int currentTime = [[_player time] intValue];
314
+ int remainingTime = [[_player remainingTime] intValue];
315
+ int duration = [_player.media.length intValue];
316
+
317
+ self.onVideoEnded(@{
318
+ @"target": self.reactTag,
319
+ @"currentTime": [NSNumber numberWithInt:currentTime],
320
+ @"remainingTime": [NSNumber numberWithInt:remainingTime],
321
+ @"duration":[NSNumber numberWithInt:duration],
322
+ @"position":[NSNumber numberWithFloat:_player.position]
323
+ });
324
+ break;
325
+ case VLCMediaPlayerStateError:
326
+ NSLog(@"VLCMediaPlayerStateError %i", _player.numberOfAudioTracks);
327
+ // This callback doesn't have any data about the error, we need to rely on the error dialog
328
+ [self _release];
329
+ break;
330
+ default:
331
+ break;
332
+ }
333
+ }
334
+ }
335
+
336
+
337
+ // ===== media delegate methods =====
338
+
339
+ - (void)mediaDidFinishParsing:(VLCMedia *)aMedia {
340
+ NSLog(@"VLCMediaDidFinishParsing %i", _player.numberOfAudioTracks);
341
+ }
342
+
343
+ - (void)mediaMetaDataDidChange:(VLCMedia *)aMedia{
344
+ NSLog(@"VLCMediaMetaDataDidChange %i", _player.numberOfAudioTracks);
345
+ }
346
+
347
+ - (void)mediaPlayer:(VLCMediaPlayer *)player recordingStoppedAtPath:(NSString *)path {
348
+ if (self.onRecordingState) {
349
+ self.onRecordingState(@{
350
+ @"target": self.reactTag,
351
+ @"isRecording": @NO,
352
+ @"recordPath": path ?: [NSNull null]
353
+ });
354
+ }
355
+ }
356
+
357
+ // ===================================
358
+
359
+ - (void)updateVideoProgress
360
+ {
361
+ if (_player && !_paused) {
362
+ int currentTime = [[_player time] intValue];
363
+ int remainingTime = [[_player remainingTime] intValue];
364
+ int duration = [_player.media.length intValue];
365
+ [self updateVideoInfo];
366
+
367
+ self.onVideoProgress(@{
368
+ @"target": self.reactTag,
369
+ @"currentTime": [NSNumber numberWithInt:currentTime],
370
+ @"remainingTime": [NSNumber numberWithInt:remainingTime],
371
+ @"duration":[NSNumber numberWithInt:duration],
372
+ @"position":[NSNumber numberWithFloat:_player.position],
373
+ });
374
+ }
375
+ }
376
+
377
+ - (void)updateVideoInfo
378
+ {
379
+ NSMutableDictionary *info = [NSMutableDictionary new];
380
+ info[@"duration"] = _player.media.length.value;
381
+ int i;
382
+ if (_player.videoSize.width > 0) {
383
+ info[@"videoSize"] = @{
384
+ @"width": @(_player.videoSize.width),
385
+ @"height": @(_player.videoSize.height)
386
+ };
387
+ }
388
+
389
+ if (_player.numberOfAudioTracks > 0) {
390
+ NSMutableArray *tracks = [NSMutableArray new];
391
+ for (i = 0; i < _player.numberOfAudioTracks; i++) {
392
+ if (_player.audioTrackIndexes[i] && _player.audioTrackNames[i]) {
393
+ [tracks addObject: @{
394
+ @"id": _player.audioTrackIndexes[i],
395
+ @"name": _player.audioTrackNames[i]
396
+ }];
397
+ }
398
+ }
399
+ info[@"audioTracks"] = tracks;
400
+ }
401
+
402
+ if (_player.numberOfSubtitlesTracks > 0) {
403
+ NSMutableArray *tracks = [NSMutableArray new];
404
+ for (i = 0; i < _player.numberOfSubtitlesTracks; i++) {
405
+ if (_player.videoSubTitlesIndexes[i] && _player.videoSubTitlesNames[i]) {
406
+ [tracks addObject: @{
407
+ @"id": _player.videoSubTitlesIndexes[i],
408
+ @"name": _player.videoSubTitlesNames[i]
409
+ }];
410
+ }
411
+ }
412
+ info[@"textTracks"] = tracks;
413
+ }
414
+
415
+ if (![_videoInfo isEqualToDictionary:info]) {
416
+ self.onVideoLoad(info);
417
+ _videoInfo = info;
418
+ }
419
+ }
420
+
421
+ - (void)jumpBackward:(int)interval
422
+ {
423
+ if (interval>=0 && interval <= [_player.media.length intValue])
424
+ [_player jumpBackward:interval];
425
+ }
426
+
427
+ - (void)jumpForward:(int)interval
428
+ {
429
+ if (interval>=0 && interval <= [_player.media.length intValue])
430
+ [_player jumpForward:interval];
431
+ }
432
+
433
+ - (void)setSeek:(float)pos
434
+ {
435
+ if ([_player isSeekable]) {
436
+ if (pos>=0 && pos <= 1) {
437
+ [_player setPosition:pos];
438
+ }
439
+ }
440
+ }
441
+
442
+ - (void)setSnapshotPath:(NSString*)path
443
+ {
444
+ if (_player)
445
+ [_player saveVideoSnapshotAt:path withWidth:0 andHeight:0];
446
+ }
447
+
448
+ - (void)setRate:(float)rate
449
+ {
450
+ [_player setRate:rate];
451
+ }
452
+
453
+ - (void)setAudioTrack:(int)track
454
+ {
455
+ [_player setCurrentAudioTrackIndex: track];
456
+ }
457
+
458
+ - (void)setTextTrack:(int)track
459
+ {
460
+ [_player setCurrentVideoSubTitleIndex:track];
461
+ }
462
+
463
+ - (void)startRecording:(NSString*)path
464
+ {
465
+ [_player startRecordingAtPath:path];
466
+ if (self.onRecordingState) {
467
+ self.onRecordingState(@{
468
+ @"target": self.reactTag,
469
+ @"isRecording": @YES
470
+ });
471
+ }
472
+ }
473
+
474
+ - (void)stopRecording
475
+ {
476
+ [_player stopRecording];
477
+ }
478
+
479
+ - (void)stopPlayer
480
+ {
481
+ [_player stop];
482
+ }
483
+
484
+ - (void)snapshot:(NSString*)path
485
+ {
486
+ @try {
487
+ if (_player) {
488
+ [_player saveVideoSnapshotAt:path withWidth:_player.videoSize.width andHeight:_player.videoSize.height];
489
+ self.onSnapshot(@{
490
+ @"success": @YES,
491
+ @"path": path,
492
+ @"error": [NSNull null],
493
+ @"target": self.reactTag
494
+ });
495
+ } else {
496
+ @throw [NSException exceptionWithName:@"PlayerNotInitialized" reason:@"Player is not initialized" userInfo:nil];
497
+ }
498
+ } @catch (NSException *e) {
499
+ NSLog(@"Error in snapshot: %@", e);
500
+ self.onSnapshot(@{
501
+ @"success": @NO,
502
+ @"error": [e description],
503
+ @"target": self.reactTag
504
+ });
505
+ }
506
+ }
507
+
508
+ - (void)setVideoAspectRatio:(NSString *)ratio{
509
+ if (!_player) return;
510
+ char *char_content = [ratio cStringUsingEncoding:NSASCIIStringEncoding];
511
+ // iOS VLC can ignore aspect-ratio changes on an active video output;
512
+ // resetting scaleFactor forces the video output to recompute geometry.
513
+ _player.scaleFactor = 0.0f;
514
+ [_player setVideoAspectRatio:char_content];
515
+ }
516
+
517
+ - (void)setMuted:(BOOL)value
518
+ {
519
+ if (_player) {
520
+ [[_player audio] setMuted:value];
521
+ }
522
+ }
523
+
524
+ #pragma mark - VLCCustomDialogRendererProtocol
525
+
526
+ - (void)showErrorWithTitle:(NSString *)title message:(NSString *)message {
527
+ NSLog(@"VLC Error - Title: %@, Message: %@", title, message);
528
+ if (self.onVideoError) {
529
+ self.onVideoError(@{
530
+ @"target": self.reactTag,
531
+ @"title": title ?: [NSNull null],
532
+ @"message": message ?: [NSNull null]
533
+ });
534
+ }
535
+ }
536
+
537
+ - (void)showLoginWithTitle:(NSString *)title
538
+ message:(NSString *)message
539
+ defaultUsername:(NSString *)username
540
+ askingForStorage:(BOOL)askingForStorage
541
+ withReference:(NSValue *)reference {
542
+ NSLog(@"VLC Login - Title: %@, Message: %@", title, message);
543
+ if (self.onVideoError) {
544
+ self.onVideoError(@{
545
+ @"target": self.reactTag,
546
+ @"title": title ?: [NSNull null],
547
+ @"message": message ?: [NSNull null]
548
+ });
549
+ }
550
+ }
551
+
552
+ - (void)showQuestionWithTitle:(NSString *)title
553
+ message:(NSString *)message
554
+ type:(VLCDialogQuestionType)type
555
+ cancelString:(NSString *)cancel
556
+ action1String:(NSString *)action1
557
+ action2String:(NSString *)action2
558
+ withReference:(NSValue *)reference {
559
+
560
+ NSLog(@"VLC Question - Title: %@, Message: %@", title, message);
561
+
562
+ // Check if this is a certificate-related dialog
563
+ NSString *fullText = [NSString stringWithFormat:@"%@ %@", title ?: @"", message ?: @""];
564
+ BOOL isCertificateDialog = [fullText containsString:@"certificate"] ||
565
+ [fullText containsString:@"SSL"] ||
566
+ [fullText containsString:@"TLS"] ||
567
+ [fullText containsString:@"cert"] ||
568
+ [fullText containsString:@"security"];
569
+
570
+ if (isCertificateDialog) {
571
+ if (_acceptInvalidCertificates) {
572
+ // Accept certificate (usually action1)
573
+ [self.dialogProvider postAction:1 forDialogReference:reference];
574
+ NSLog(@"iOS: Auto-accepted certificate dialog");
575
+ } else {
576
+ // Reject certificate (cancel)
577
+ [self.dialogProvider postAction:3 forDialogReference:reference]; // Cancel
578
+ NSLog(@"iOS: Rejected certificate dialog");
579
+ }
580
+ } else {
581
+ // For other dialogs, default to cancel
582
+ [self.dialogProvider postAction:3 forDialogReference:reference];
583
+ }
584
+ }
585
+
586
+ - (void)showProgressWithTitle:(NSString *)title
587
+ message:(NSString *)message
588
+ isIndeterminate:(BOOL)indeterminate
589
+ position:(float)position
590
+ cancelString:(NSString *)cancel
591
+ withReference:(NSValue *)reference {
592
+ NSLog(@"VLC Progress - Title: %@, Message: %@, Position: %.2f", title, message, position);
593
+ // Handle progress dialog if needed
594
+ }
595
+
596
+ - (void)updateProgressWithReference:(NSValue *)reference
597
+ message:(NSString *)message
598
+ position:(float)position {
599
+ // Update progress dialog
600
+ }
601
+
602
+ - (void)cancelDialogWithReference:(NSValue *)reference {
603
+ NSLog(@"VLC Dialog cancelled");
604
+ // Handle dialog cancellation
605
+ }
606
+
607
+ - (void)setAcceptInvalidCertificates:(BOOL)accept
608
+ {
609
+ _acceptInvalidCertificates = accept;
610
+ NSLog(@"iOS: Set acceptInvalidCertificates to %@", accept ? @"YES" : @"NO");
611
+ }
612
+
613
+ - (void)_release
614
+ {
615
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
616
+
617
+ if (_player.media)
618
+ [_player stop];
619
+
620
+ if (_player)
621
+ _player = nil;
622
+
623
+ _eventDispatcher = nil;
624
+ }
625
+
626
+
627
+ #pragma mark - Lifecycle
628
+ - (void)removeFromSuperview
629
+ {
630
+ NSLog(@"removeFromSuperview");
631
+ [self _release];
632
+ [super removeFromSuperview];
633
+ }
634
+
635
+ @end
@@ -0,0 +1,5 @@
1
+ #import "React/RCTViewManager.h"
2
+
3
+ @interface RCTVLCPlayerManager : RCTViewManager
4
+
5
+ @end