@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.
- package/.github/CODEOWNERS +2 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +38 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
- package/.github/ISSUE_TEMPLATE/question.md +11 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +15 -0
- package/CODE_OF_CONDUCT.md +128 -0
- package/LICENSE +21 -0
- package/README.md +425 -0
- package/RNJWPlayer.podspec +44 -0
- package/android/.gradle/8.1.1/checksums/checksums.lock +0 -0
- package/android/.gradle/8.1.1/dependencies-accessors/dependencies-accessors.lock +0 -0
- package/android/.gradle/8.1.1/dependencies-accessors/gc.properties +0 -0
- package/android/.gradle/8.1.1/fileChanges/last-build.bin +0 -0
- package/android/.gradle/8.1.1/fileHashes/fileHashes.lock +0 -0
- package/android/.gradle/8.1.1/gc.properties +0 -0
- package/android/.gradle/8.2/checksums/checksums.lock +0 -0
- package/android/.gradle/8.2/dependencies-accessors/dependencies-accessors.lock +0 -0
- package/android/.gradle/8.2/dependencies-accessors/gc.properties +0 -0
- package/android/.gradle/8.2/fileChanges/last-build.bin +0 -0
- package/android/.gradle/8.2/fileHashes/fileHashes.lock +0 -0
- package/android/.gradle/8.2/gc.properties +0 -0
- package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
- package/android/.gradle/buildOutputCleanup/cache.properties +2 -0
- package/android/.gradle/config.properties +2 -0
- package/android/.gradle/vcs-1/gc.properties +0 -0
- package/android/.idea/gradle.xml +12 -0
- package/android/.idea/migrations.xml +10 -0
- package/android/.idea/misc.xml +10 -0
- package/android/.idea/vcs.xml +6 -0
- package/android/.idea/workspace.xml +54 -0
- package/android/build.gradle +110 -0
- package/android/local.properties +8 -0
- package/android/src/main/AndroidManifest.xml +25 -0
- package/android/src/main/java/com/jwplayer/rnjwplayer/ArrayUtil.java +129 -0
- package/android/src/main/java/com/jwplayer/rnjwplayer/CastOptionsProvider.java +55 -0
- package/android/src/main/java/com/jwplayer/rnjwplayer/MapUtil.java +136 -0
- package/android/src/main/java/com/jwplayer/rnjwplayer/RNJWPlayer.java +76 -0
- package/android/src/main/java/com/jwplayer/rnjwplayer/RNJWPlayerAds.java +239 -0
- package/android/src/main/java/com/jwplayer/rnjwplayer/RNJWPlayerModule.java +526 -0
- package/android/src/main/java/com/jwplayer/rnjwplayer/RNJWPlayerPackage.java +30 -0
- package/android/src/main/java/com/jwplayer/rnjwplayer/RNJWPlayerView.java +1499 -0
- package/android/src/main/java/com/jwplayer/rnjwplayer/RNJWPlayerViewManager.java +171 -0
- package/android/src/main/java/com/jwplayer/rnjwplayer/Util.java +219 -0
- package/android/src/main/java/com/jwplayer/rnjwplayer/WidevineCallback.java +62 -0
- package/badges/license.svg +1 -0
- package/badges/version.svg +1 -0
- package/docs/legacy_readme.md +634 -0
- package/docs/props.md +43 -0
- package/docs/types.md +254 -0
- package/index.d.ts +564 -0
- package/index.js +699 -0
- package/ios/RNJWPlayer/RCTConvert+RNJWPlayer.swift +119 -0
- package/ios/RNJWPlayer/RNJWPlayer-Bridging-Header.h +5 -0
- package/ios/RNJWPlayer/RNJWPlayerAds.swift +260 -0
- package/ios/RNJWPlayer/RNJWPlayerModels.swift +149 -0
- package/ios/RNJWPlayer/RNJWPlayerView.swift +1837 -0
- package/ios/RNJWPlayer/RNJWPlayerViewController.swift +616 -0
- package/ios/RNJWPlayer/RNJWPlayerViewManager.m +132 -0
- package/ios/RNJWPlayer/RNJWPlayerViewManager.swift +500 -0
- package/ios/RNJWPlayer.xcodeproj/project.pbxproj +323 -0
- 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
|
+
}
|