@jwplayer/jwplayer-react-native 1.0.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 (61) hide show
  1. package/.github/CODEOWNERS +2 -0
  2. package/.github/ISSUE_TEMPLATE/bug_report.md +38 -0
  3. package/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
  4. package/.github/ISSUE_TEMPLATE/question.md +11 -0
  5. package/.github/PULL_REQUEST_TEMPLATE.md +15 -0
  6. package/CODE_OF_CONDUCT.md +128 -0
  7. package/LICENSE +21 -0
  8. package/README.md +425 -0
  9. package/RNJWPlayer.podspec +44 -0
  10. package/android/.gradle/8.1.1/checksums/checksums.lock +0 -0
  11. package/android/.gradle/8.1.1/dependencies-accessors/dependencies-accessors.lock +0 -0
  12. package/android/.gradle/8.1.1/dependencies-accessors/gc.properties +0 -0
  13. package/android/.gradle/8.1.1/fileChanges/last-build.bin +0 -0
  14. package/android/.gradle/8.1.1/fileHashes/fileHashes.lock +0 -0
  15. package/android/.gradle/8.1.1/gc.properties +0 -0
  16. package/android/.gradle/8.2/checksums/checksums.lock +0 -0
  17. package/android/.gradle/8.2/dependencies-accessors/dependencies-accessors.lock +0 -0
  18. package/android/.gradle/8.2/dependencies-accessors/gc.properties +0 -0
  19. package/android/.gradle/8.2/fileChanges/last-build.bin +0 -0
  20. package/android/.gradle/8.2/fileHashes/fileHashes.lock +0 -0
  21. package/android/.gradle/8.2/gc.properties +0 -0
  22. package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
  23. package/android/.gradle/buildOutputCleanup/cache.properties +2 -0
  24. package/android/.gradle/config.properties +2 -0
  25. package/android/.gradle/vcs-1/gc.properties +0 -0
  26. package/android/.idea/gradle.xml +12 -0
  27. package/android/.idea/migrations.xml +10 -0
  28. package/android/.idea/misc.xml +10 -0
  29. package/android/.idea/vcs.xml +6 -0
  30. package/android/.idea/workspace.xml +54 -0
  31. package/android/build.gradle +110 -0
  32. package/android/local.properties +8 -0
  33. package/android/src/main/AndroidManifest.xml +25 -0
  34. package/android/src/main/java/com/jwplayer/rnjwplayer/ArrayUtil.java +129 -0
  35. package/android/src/main/java/com/jwplayer/rnjwplayer/CastOptionsProvider.java +55 -0
  36. package/android/src/main/java/com/jwplayer/rnjwplayer/MapUtil.java +136 -0
  37. package/android/src/main/java/com/jwplayer/rnjwplayer/RNJWPlayer.java +76 -0
  38. package/android/src/main/java/com/jwplayer/rnjwplayer/RNJWPlayerAds.java +239 -0
  39. package/android/src/main/java/com/jwplayer/rnjwplayer/RNJWPlayerModule.java +526 -0
  40. package/android/src/main/java/com/jwplayer/rnjwplayer/RNJWPlayerPackage.java +30 -0
  41. package/android/src/main/java/com/jwplayer/rnjwplayer/RNJWPlayerView.java +1499 -0
  42. package/android/src/main/java/com/jwplayer/rnjwplayer/RNJWPlayerViewManager.java +171 -0
  43. package/android/src/main/java/com/jwplayer/rnjwplayer/Util.java +219 -0
  44. package/android/src/main/java/com/jwplayer/rnjwplayer/WidevineCallback.java +62 -0
  45. package/badges/license.svg +1 -0
  46. package/badges/version.svg +1 -0
  47. package/docs/legacy_readme.md +634 -0
  48. package/docs/props.md +43 -0
  49. package/docs/types.md +254 -0
  50. package/index.d.ts +564 -0
  51. package/index.js +699 -0
  52. package/ios/RNJWPlayer/RCTConvert+RNJWPlayer.swift +119 -0
  53. package/ios/RNJWPlayer/RNJWPlayer-Bridging-Header.h +5 -0
  54. package/ios/RNJWPlayer/RNJWPlayerAds.swift +260 -0
  55. package/ios/RNJWPlayer/RNJWPlayerModels.swift +149 -0
  56. package/ios/RNJWPlayer/RNJWPlayerView.swift +1837 -0
  57. package/ios/RNJWPlayer/RNJWPlayerViewController.swift +616 -0
  58. package/ios/RNJWPlayer/RNJWPlayerViewManager.m +132 -0
  59. package/ios/RNJWPlayer/RNJWPlayerViewManager.swift +500 -0
  60. package/ios/RNJWPlayer.xcodeproj/project.pbxproj +323 -0
  61. package/package.json +45 -0
@@ -0,0 +1,616 @@
1
+ //
2
+ // RNJWPlayerViewController.m
3
+ // RNJWPlayer
4
+ //
5
+ // Created by Chaim Paneth on 3/30/22.
6
+ //
7
+
8
+ import UIKit
9
+ import AVFoundation
10
+ import AVKit
11
+ import MediaPlayer
12
+ import React
13
+ import GoogleCast
14
+ import JWPlayerKit
15
+
16
+ class RNJWPlayerViewController : JWPlayerViewController, JWPlayerViewControllerDelegate, JWDRMContentKeyDataSource {
17
+
18
+ var parentView:RNJWPlayerView!
19
+
20
+ func setDelegates() {
21
+ self.delegate = self
22
+ // self.playerView.delegate = self
23
+ // self.player.delegate = self
24
+ // self.player.playbackStateDelegate = self
25
+ // self.player.adDelegate = self
26
+ // self.player.avDelegate = self
27
+ self.player.contentKeyDataSource = self
28
+ }
29
+
30
+ func removeDelegates() {
31
+ self.delegate = nil
32
+ // self.playerView.delegate = nil
33
+ // self.player.delegate = nil
34
+ // self.player.playbackStateDelegate = nil
35
+ // self.player.adDelegate = nil
36
+ // self.player.avDelegate = nil
37
+ self.player.contentKeyDataSource = nil
38
+ }
39
+
40
+ // MARK: - JWPlayer Delegate
41
+
42
+ override func jwplayerIsReady(_ player:JWPlayer) {
43
+ super.jwplayerIsReady(player)
44
+
45
+ parentView?.settingConfig = false
46
+ parentView?.onPlayerReady?([:])
47
+
48
+ if parentView?.pendingConfig == true && (parentView?.currentConfig != nil) {
49
+ parentView?.setConfig(parentView!.currentConfig)
50
+ }
51
+ }
52
+
53
+ override func jwplayer(_ player:JWPlayer, failedWithError code:UInt, message:String) {
54
+ super.jwplayer(player, failedWithError:code, message:message)
55
+ parentView?.onPlayerError?(["error": message])
56
+ parentView?.playerFailed = true
57
+ }
58
+
59
+ override func jwplayer(_ player:JWPlayer, failedWithSetupError code:UInt, message:String) {
60
+ super.jwplayer(player, failedWithSetupError:code, message:message)
61
+ parentView?.onSetupPlayerError?(["error": message])
62
+ parentView?.playerFailed = true
63
+ }
64
+
65
+ override func jwplayer(_ player:JWPlayer, encounteredWarning code:UInt, message:String) {
66
+ super.jwplayer(player, encounteredWarning:code, message:message)
67
+ parentView?.onPlayerWarning?(["warning": message])
68
+ }
69
+
70
+ override func jwplayer(_ player:JWPlayer, encounteredAdError code:UInt, message:String) {
71
+ super.jwplayer(player, encounteredAdError:code, message:message)
72
+ parentView?.onPlayerAdError?(["error": message])
73
+ }
74
+
75
+
76
+ override func jwplayer(_ player:JWPlayer, encounteredAdWarning code:UInt, message:String) {
77
+ super.jwplayer(player, encounteredAdWarning:code, message:message)
78
+ parentView?.onPlayerAdWarning?(["warning": message])
79
+ }
80
+
81
+
82
+ // MARK: - JWPlayer View Delegate
83
+
84
+ override func playerView(_ view:JWPlayerView, sizeChangedFrom oldSize:CGSize, to newSize:CGSize) {
85
+ let oldSizeDict: [String: Any] = [
86
+ "width": oldSize.width,
87
+ "height": oldSize.height
88
+ ]
89
+
90
+ let newSizeDict: [String: Any] = [
91
+ "width": newSize.width,
92
+ "height": newSize.height
93
+ ]
94
+
95
+ let sizesDict: [String: Any] = [
96
+ "oldSize": oldSizeDict,
97
+ "newSize": newSizeDict
98
+ ]
99
+
100
+ do {
101
+ let data = try JSONSerialization.data(withJSONObject: sizesDict, options: .prettyPrinted)
102
+ parentView?.onPlayerSizeChange?(["sizes": data])
103
+ } catch {
104
+ print("Error converting dictionary to JSON data: \(error)")
105
+ }
106
+ }
107
+
108
+ // MARK: - JWPlayer View Controller Delegate
109
+
110
+ func playerViewController(_ controller:JWPlayerViewController, sizeChangedFrom oldSize:CGSize, to newSize:CGSize) {
111
+ let oldSizeDict: [String: Any] = [
112
+ "width": oldSize.width,
113
+ "height": oldSize.height
114
+ ]
115
+
116
+ let newSizeDict: [String: Any] = [
117
+ "width": newSize.width,
118
+ "height": newSize.height
119
+ ]
120
+
121
+ let sizesDict: [String: Any] = [
122
+ "oldSize": oldSizeDict,
123
+ "newSize": newSizeDict
124
+ ]
125
+
126
+ do {
127
+ let data = try JSONSerialization.data(withJSONObject: sizesDict, options: .prettyPrinted)
128
+ parentView?.onPlayerSizeChange?(["sizes": data])
129
+ } catch {
130
+ print("Error converting dictionary to JSON data: \(error)")
131
+ }
132
+ }
133
+
134
+ func playerViewController(_ controller:JWPlayerViewController, screenTappedAt position:CGPoint) {
135
+ parentView?.onScreenTapped?(["x": position.x, "y": position.y])
136
+ }
137
+
138
+ func playerViewController(_ controller:JWPlayerViewController, controlBarVisibilityChanged isVisible:Bool, frame:CGRect) {
139
+ parentView?.onControlBarVisible?(["visible": isVisible])
140
+ }
141
+
142
+ func playerViewControllerWillGoFullScreen(_ controller:JWPlayerViewController) -> JWFullScreenViewController? {
143
+ parentView?.onFullScreenRequested?([:])
144
+ return nil
145
+ }
146
+
147
+ func playerViewControllerDidGoFullScreen(_ controller:JWPlayerViewController) {
148
+ parentView?.onFullScreen?([:])
149
+ }
150
+
151
+ func playerViewControllerWillDismissFullScreen(_ controller:JWPlayerViewController) {
152
+ parentView?.onFullScreenExitRequested?([:])
153
+ }
154
+
155
+ func playerViewControllerDidDismissFullScreen(_ controller:JWPlayerViewController) {
156
+ parentView?.onFullScreenExit?([:])
157
+ }
158
+
159
+ func playerViewController(_ controller:JWPlayerViewController, relatedMenuClosedWithMethod method:JWRelatedInteraction) {
160
+
161
+ }
162
+
163
+ func playerViewController(_ controller: JWPlayerKit.JWPlayerViewController, relatedMenuOpenedWithItems items: [JWPlayerKit.JWPlayerItem], withMethod method: JWPlayerKit.JWRelatedInteraction) {
164
+
165
+ }
166
+
167
+ func playerViewController(_ controller: JWPlayerKit.JWPlayerViewController, relatedItemBeganPlaying item: JWPlayerKit.JWPlayerItem, atIndex index: Int, withMethod method: JWPlayerKit.JWRelatedMethod) {
168
+
169
+ }
170
+
171
+ // MARK: Time events
172
+
173
+ func onAdTimeEvent(time:JWTimeData) {
174
+ super.onAdTimeEvent(time)
175
+ parentView?.onAdTime?(["position": time.position, "duration": time.duration])
176
+ }
177
+
178
+ func onMediaTimeEvent(time:JWTimeData) {
179
+ super.onMediaTimeEvent(time)
180
+ parentView?.onTime?(["position": time.position, "duration": time.duration])
181
+ }
182
+
183
+ // MARK: - DRM Delegate
184
+
185
+ func contentIdentifierForURL(_ url: URL, completionHandler handler: @escaping (Data?) -> Void) {
186
+ let data:Data! = url.host?.data(using: String.Encoding.utf8)
187
+ handler(data)
188
+ }
189
+
190
+ func appIdentifierForURL(_ url: URL, completionHandler handler: @escaping (Data?) -> Void) {
191
+ guard let fairplayCertUrlString = parentView?.fairplayCertUrl, let fairplayCertUrl = URL(string: fairplayCertUrlString) else {
192
+ return
193
+ }
194
+
195
+ let request = URLRequest(url: fairplayCertUrl)
196
+ let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
197
+ if let error = error {
198
+ print("DRM cert request error - \(error.localizedDescription)")
199
+ }
200
+ handler(data)
201
+ }
202
+ task.resume()
203
+ }
204
+
205
+ func contentKeyWithSPCData(_ spcData: Data, completionHandler handler: @escaping (Data?, Date?, String?) -> Void) {
206
+ if parentView?.processSpcUrl == nil {
207
+ return
208
+ }
209
+
210
+ if let processSpcUrl = parentView?.processSpcUrl {
211
+ let ckcRequest = NSMutableURLRequest(url: NSURL(string: processSpcUrl)! as URL)
212
+ ckcRequest.httpMethod = "POST"
213
+ ckcRequest.httpBody = spcData
214
+ ckcRequest.addValue("application/octet-stream", forHTTPHeaderField: "Content-Type")
215
+
216
+ URLSession.shared.dataTask(with: ckcRequest as URLRequest) { (data, response, error) in
217
+ if let httpResponse = response as? HTTPURLResponse, (error != nil || httpResponse.statusCode != 200) {
218
+ NSLog("DRM ckc request error - %@", error.debugDescription)
219
+ handler(nil, nil, nil)
220
+ return
221
+ }
222
+
223
+ handler(data, nil, "application/octet-stream")
224
+ }.resume()
225
+ }
226
+ }
227
+
228
+ // MARK: - AV Picture In Picture Delegate
229
+
230
+ override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
231
+ super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
232
+ // if (keyPath == "playbackLikelyToKeepUp") {
233
+ // parentView?.playerViewController.player.play()
234
+ // }
235
+ }
236
+
237
+ override func pictureInPictureControllerDidStopPictureInPicture(_ pictureInPictureController:AVPictureInPictureController) {
238
+ super.pictureInPictureControllerDidStopPictureInPicture(pictureInPictureController)
239
+ }
240
+
241
+ override func pictureInPictureControllerDidStartPictureInPicture(_ pictureInPictureController:AVPictureInPictureController) {
242
+ super.pictureInPictureControllerDidStartPictureInPicture(pictureInPictureController)
243
+ }
244
+
245
+ override func pictureInPictureControllerWillStopPictureInPicture(_ pictureInPictureController:AVPictureInPictureController) {
246
+ super.pictureInPictureControllerWillStopPictureInPicture(pictureInPictureController)
247
+ }
248
+
249
+ override func pictureInPictureController(_ pictureInPictureController: AVPictureInPictureController, failedToStartPictureInPictureWithError error: Error) {
250
+ super.pictureInPictureController(pictureInPictureController, failedToStartPictureInPictureWithError: error)
251
+ }
252
+
253
+ override func pictureInPictureControllerWillStartPictureInPicture(_ pictureInPictureController:AVPictureInPictureController) {
254
+ super.pictureInPictureControllerWillStartPictureInPicture(pictureInPictureController)
255
+ }
256
+
257
+ override func pictureInPictureController(_ pictureInPictureController:AVPictureInPictureController, restoreUserInterfaceForPictureInPictureStopWithCompletionHandler completionHandler:@escaping (Bool) -> Void) {
258
+ super.pictureInPictureController(pictureInPictureController, restoreUserInterfaceForPictureInPictureStopWithCompletionHandler: completionHandler)
259
+ }
260
+
261
+ // MARK: - JWPlayer State Delegate
262
+
263
+ override func jwplayerContentIsBuffering(_ player:JWPlayer) {
264
+ super.jwplayerContentIsBuffering(player)
265
+ parentView?.onBuffer?([:])
266
+ }
267
+
268
+ override func jwplayer(_ player:JWPlayer, isBufferingWithReason reason:JWBufferReason) {
269
+ super.jwplayer(player, isBufferingWithReason:reason)
270
+ parentView?.onBuffer?([:])
271
+ }
272
+
273
+ override func jwplayer(_ player:JWPlayer, updatedBuffer percent:Double, position time:JWTimeData) {
274
+ super.jwplayer(player, updatedBuffer:percent, position:time)
275
+ parentView?.onUpdateBuffer?(["percent": percent, "position": time as Any])
276
+ }
277
+
278
+ override func jwplayer(_ player:JWPlayer, didFinishLoadingWithTime loadTime:TimeInterval) {
279
+ super.jwplayer(player, didFinishLoadingWithTime:loadTime)
280
+ parentView?.onLoaded?([:])
281
+ }
282
+
283
+ override func jwplayer(_ player:JWPlayer, isAttemptingToPlay playlistItem:JWPlayerItem, reason:JWPlayReason) {
284
+ super.jwplayer(player, isAttemptingToPlay:playlistItem, reason:reason)
285
+ parentView?.onAttemptPlay?([:])
286
+ }
287
+
288
+ override func jwplayer(_ player:JWPlayer, isPlayingWithReason reason:JWPlayReason) {
289
+ super.jwplayer(player, isPlayingWithReason:reason)
290
+
291
+ parentView?.onPlay?([:])
292
+
293
+ parentView?.userPaused = false
294
+ parentView?.wasInterrupted = false
295
+ }
296
+
297
+ override func jwplayer(_ player:JWPlayer, willPlayWithReason reason:JWPlayReason) {
298
+ super.jwplayer(player, willPlayWithReason:reason)
299
+ parentView?.onBeforePlay?([:])
300
+ }
301
+
302
+ override func jwplayer(_ player:JWPlayer, didPauseWithReason reason:JWPauseReason) {
303
+ super.jwplayer(player, didPauseWithReason:reason)
304
+ parentView?.onPause?([:])
305
+
306
+ if let wasInterrupted = parentView?.wasInterrupted {
307
+ if !wasInterrupted {
308
+ parentView?.userPaused = true
309
+ }
310
+ }
311
+ }
312
+
313
+ override func jwplayer(_ player:JWPlayer, didBecomeIdleWithReason reason:JWIdleReason) {
314
+ super.jwplayer(player, didBecomeIdleWithReason:reason)
315
+ parentView?.onIdle?([:])
316
+ }
317
+
318
+ override func jwplayer(_ player:JWPlayer, isVisible:Bool) {
319
+ super.jwplayer(player, isVisible:isVisible)
320
+ parentView?.onVisible?(["visible": isVisible])
321
+ }
322
+
323
+ override func jwplayerContentWillComplete(_ player:JWPlayer) {
324
+ super.jwplayerContentWillComplete(player)
325
+ parentView?.onBeforeComplete?([:])
326
+ }
327
+
328
+ override func jwplayerContentDidComplete(_ player:JWPlayer) {
329
+ super.jwplayerContentDidComplete(player)
330
+ parentView?.onComplete?([:])
331
+ }
332
+
333
+ override func jwplayer(_ player:JWPlayer, didLoadPlaylistItem item:JWPlayerItem, at index:UInt) {
334
+ super.jwplayer(player, didLoadPlaylistItem: item, at: index)
335
+
336
+ // var sourceDict: [String: Any] = [:]
337
+ // var file: String?
338
+ //
339
+ // for source in item.videoSources {
340
+ // sourceDict["file"] = source.file?.absoluteString
341
+ // sourceDict["label"] = source.label
342
+ // sourceDict["default"] = source.defaultVideo
343
+ //
344
+ // if source.defaultVideo {
345
+ // file = source.file?.absoluteString
346
+ // }
347
+ // }
348
+ //
349
+ // var schedDict: [String: Any] = [:]
350
+ //
351
+ // if let schedules = item.adSchedule {
352
+ // for sched in schedules {
353
+ // schedDict["offset"] = sched.offset
354
+ // schedDict["tags"] = sched.tags
355
+ // schedDict["type"] = sched.type
356
+ // }
357
+ // }
358
+ //
359
+ // var trackDict: [String: Any] = [:]
360
+ //
361
+ // if let tracks = item.mediaTracks {
362
+ // for track in tracks {
363
+ // trackDict["file"] = track.file?.absoluteString
364
+ // trackDict["label"] = track.label
365
+ // trackDict["default"] = track.defaultTrack
366
+ // }
367
+ // }
368
+ //
369
+ // let itemDict: [String: Any] = [
370
+ // "file": file ?? "",
371
+ // "mediaId": item.mediaId as Any,
372
+ // "title": item.title as Any,
373
+ // "description": item.description,
374
+ // "image": item.posterImage?.absoluteString ?? "",
375
+ // "startTime": item.startTime,
376
+ // "adVmap": item.vmapURL?.absoluteString ?? "",
377
+ // "recommendations": item.recommendations?.absoluteString ?? "",
378
+ // "sources": sourceDict,
379
+ // "adSchedule": schedDict,
380
+ // "tracks": trackDict
381
+ // ]
382
+
383
+ do {
384
+ let data:Data! = try JSONSerialization.data(withJSONObject: item.toJSONObject(), options:.prettyPrinted)
385
+
386
+ parentView?.onPlaylistItem?(["playlistItem": String(data:data, encoding:String.Encoding.utf8) as Any, "index": index])
387
+ } catch {
388
+ print("Error converting dictionary to JSON data: \(error)")
389
+ }
390
+
391
+ // item.addObserver(self, forKeyPath:"playbackLikelyToKeepUp", options:.new, context:nil)
392
+ }
393
+
394
+ override func jwplayer(_ player:JWPlayer, didLoadPlaylist playlist:[JWPlayerItem]) {
395
+ super.jwplayer(player, didLoadPlaylist: playlist)
396
+
397
+ let playlistArray:NSMutableArray! = NSMutableArray()
398
+
399
+ for item:JWPlayerItem? in playlist {
400
+ // var file:String!
401
+ //
402
+ // var sourceDict: [String: Any] = [:]
403
+ //
404
+ // for source in item?.videoSources ?? [] {
405
+ // sourceDict["file"] = source.file?.absoluteString
406
+ // sourceDict["label"] = source.label
407
+ // sourceDict["default"] = source.defaultVideo
408
+ //
409
+ // if source.defaultVideo {
410
+ // file = source.file?.absoluteString ?? ""
411
+ // }
412
+ // }
413
+ //
414
+ // var schedDict: [String: Any] = [:]
415
+ // if let adSchedule = item?.adSchedule {
416
+ // for sched in adSchedule {
417
+ // schedDict["offset"] = sched.offset
418
+ // schedDict["tags"] = sched.tags
419
+ // schedDict["type"] = sched.type
420
+ // }
421
+ // }
422
+ //
423
+ // var trackDict: [String: Any] = [:]
424
+ //
425
+ // if let mediaTracks = item?.mediaTracks {
426
+ // for track in mediaTracks {
427
+ // trackDict["file"] = track.file?.absoluteString
428
+ // trackDict["label"] = track.label
429
+ // trackDict["default"] = track.defaultTrack
430
+ // }
431
+ // }
432
+ //
433
+ // let itemDict: [String: Any] = [
434
+ // "file": file ?? "",
435
+ // "mediaId": item?.mediaId ?? "",
436
+ // "title": item?.title ?? "",
437
+ // "description": item?.description ?? "",
438
+ // "image": item?.posterImage?.absoluteString ?? "",
439
+ // "startTime": item?.startTime ?? 0,
440
+ // "adVmap": item?.vmapURL?.absoluteString ?? "",
441
+ // "recommendations": item?.recommendations?.absoluteString ?? "",
442
+ // "sources": sourceDict as Any,
443
+ // "adSchedule": trackDict,
444
+ // "tracks": schedDict
445
+ // ]
446
+
447
+ playlistArray.add(item?.toJSONObject() as Any)
448
+ }
449
+
450
+ do {
451
+ let data:Data! = try JSONSerialization.data(withJSONObject: playlistArray as Any, options:.prettyPrinted)
452
+
453
+ parentView?.onPlaylist?(["playlist": String(data:data as Data, encoding:String.Encoding.utf8) as Any])
454
+ } catch {
455
+ print("Error converting dictionary to JSON data: \(error)")
456
+ }
457
+ }
458
+
459
+ override func jwplayerPlaylistHasCompleted(_ player:JWPlayer) {
460
+ super.jwplayerPlaylistHasCompleted(player)
461
+ parentView?.onPlaylistComplete?([:])
462
+ }
463
+
464
+ override func jwplayer(_ player:JWPlayer, usesMediaType type:JWMediaType) {
465
+ super.jwplayer(player, usesMediaType:type)
466
+ }
467
+
468
+ override func jwplayer(_ player:JWPlayer, seekedFrom oldPosition:TimeInterval, to newPosition:TimeInterval) {
469
+ super.jwplayer(player, seekedFrom:oldPosition, to:newPosition)
470
+ parentView?.onSeek?(["from": oldPosition, "to": newPosition])
471
+ }
472
+
473
+ override func jwplayerHasSeeked(_ player:JWPlayer) {
474
+ super.jwplayerHasSeeked(player)
475
+ parentView?.onSeeked?([:])
476
+ }
477
+
478
+ override func jwplayer(_ player:JWPlayer, playbackRateChangedTo rate:Double, at time:TimeInterval) {
479
+ super.jwplayer(player, playbackRateChangedTo:rate, at:time)
480
+ parentView?.onRateChanged?(["rate": rate, "at": time])
481
+ }
482
+
483
+ override func jwplayer(_ player:JWPlayer, updatedCues cues:[JWCue]) {
484
+ super.jwplayer(player, updatedCues:cues)
485
+ }
486
+
487
+ // MARK: - JWPlayer Ad Delegate
488
+
489
+ override func jwplayer(_ player: JWPlayer, adEvent event: JWAdEvent) {
490
+ super.jwplayer(player, adEvent:event)
491
+ parentView?.onAdEvent?(["client": event.client, "type": event.type])
492
+ }
493
+
494
+ // MARK: - JWPlayer Cast Delegate
495
+
496
+ override func castController(_ controller:JWCastController, castingBeganWithDevice device:JWCastingDevice) {
497
+ super.castController(controller, castingBeganWithDevice:device)
498
+ parentView?.onCasting?([:])
499
+ }
500
+
501
+ override func castController(_ controller:JWCastController, castingEndedWithError error: Error?) {
502
+ super.castController(controller, castingEndedWithError:error)
503
+ parentView?.onCastingEnded?(["error": error as Any])
504
+ }
505
+
506
+ override func castController(_ controller:JWCastController, castingFailedWithError error: Error) {
507
+ super.castController(controller, castingFailedWithError:error)
508
+ parentView?.onCastingFailed?(["error": error as Any])
509
+ }
510
+
511
+ override func castController(_ controller:JWCastController, connectedTo device: JWCastingDevice) {
512
+ super.castController(controller, connectedTo:device)
513
+ let dict:NSMutableDictionary! = NSMutableDictionary()
514
+
515
+ dict.setObject(device.name, forKey:"name" as NSCopying)
516
+ dict.setObject(device.identifier, forKey:"identifier" as NSCopying)
517
+
518
+ do {
519
+ let data:Data! = try JSONSerialization.data(withJSONObject: dict as Any, options:.prettyPrinted)
520
+
521
+ parentView?.onConnectedToCastingDevice?(["device": String(data:data as Data, encoding:String.Encoding.utf8) as Any])
522
+ } catch {
523
+ print("Error converting dictionary to JSON data: \(error)")
524
+ }
525
+ }
526
+
527
+ override func castController(_ controller:JWCastController, connectionFailedWithError error: Error) {
528
+ super.castController(controller, connectionFailedWithError:error)
529
+ parentView?.onConnectionFailed?(["error": error as Any])
530
+ }
531
+
532
+ override func castController(_ controller:JWCastController, connectionRecoveredWithDevice device:JWCastingDevice) {
533
+ super.castController(controller, connectionRecoveredWithDevice:device)
534
+ parentView?.onConnectionRecovered?([:])
535
+ }
536
+
537
+ override func castController(_ controller:JWCastController, connectionSuspendedWithDevice device:JWCastingDevice) {
538
+ super.castController(controller, connectionSuspendedWithDevice:device)
539
+ parentView?.onConnectionTemporarilySuspended?([:])
540
+ }
541
+
542
+ override func castController(_ controller: JWCastController, devicesAvailable devices:[JWCastingDevice]) {
543
+ super.castController(controller, devicesAvailable:devices)
544
+ parentView?.availableDevices = devices
545
+
546
+ var devicesInfo: [[String: Any]] = []
547
+ for device in devices {
548
+ var dict: [String: Any] = [:]
549
+
550
+ dict["name"] = device.name
551
+ dict["identifier"] = device.identifier
552
+
553
+ devicesInfo.append(dict)
554
+ }
555
+
556
+ do {
557
+ let data:Data! = try JSONSerialization.data(withJSONObject: devicesInfo as Any, options:.prettyPrinted)
558
+
559
+ parentView?.onCastingDevicesAvailable?(["devices": String(data:data as Data, encoding:String.Encoding.utf8) as Any])
560
+ } catch {
561
+ print("Error converting dictionary to JSON data: \(error)")
562
+ }
563
+ }
564
+
565
+ override func castController(_ controller: JWCastController, disconnectedWithError error: (Error)?) {
566
+ super.castController(controller, disconnectedWithError:error)
567
+ parentView?.onDisconnectedFromCastingDevice?(["error": error as Any])
568
+ }
569
+
570
+ // MARK: - JWPlayer AV Delegate
571
+
572
+ override func jwplayer(_ player:JWPlayer, audioTracksUpdated levels:[JWMediaSelectionOption]) {
573
+ super.jwplayer(player, audioTracksUpdated:levels)
574
+ parentView?.onAudioTracks?([:])
575
+ }
576
+
577
+ override func jwplayer(_ player:JWPlayer, audioTrackChanged currentLevel:Int) {
578
+ super.jwplayer(player, audioTrackChanged:currentLevel)
579
+ }
580
+
581
+ override func jwplayer(_ player:JWPlayer, captionPresented caption:[String], at time:JWTimeData) {
582
+ super.jwplayer(player, captionPresented:caption, at:time)
583
+ }
584
+
585
+ override func jwplayer(_ player:JWPlayer, captionTrackChanged index:Int) {
586
+ super.jwplayer(player, captionTrackChanged:index)
587
+ }
588
+
589
+ override func jwplayer(_ player:JWPlayer, qualityLevelChanged currentLevel:Int) {
590
+ super.jwplayer(player, qualityLevelChanged:currentLevel)
591
+ }
592
+
593
+ override func jwplayer(_ player:JWPlayer, qualityLevelsUpdated levels:[JWVideoSource]) {
594
+ super.jwplayer(player, qualityLevelsUpdated:levels)
595
+ }
596
+
597
+ override func jwplayer(_ player:JWPlayer, updatedCaptionList options:[JWMediaSelectionOption]) {
598
+ super.jwplayer(player, updatedCaptionList:options)
599
+ }
600
+
601
+ override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
602
+ super.viewWillTransition(to: size, with: coordinator)
603
+ coordinator.animate(alongsideTransition: { _ in
604
+ let orientation = UIDevice.current.orientation
605
+ switch orientation {
606
+ case .portrait, .portraitUpsideDown:
607
+ if self.parentView?.currentConfig["exitFullScreenOnPortrait"] as? Bool ?? false {
608
+ super.dismissFullScreen(animated: true)
609
+ }
610
+ default:
611
+ break
612
+ }
613
+ })
614
+ }
615
+
616
+ }