@takeoffmedia/react-native-penthera 0.1.13 → 0.2.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/ios/Catalog.swift +2 -0
- package/ios/Penthera copy.swift +501 -0
- package/ios/Penthera.m +0 -4
- package/ios/Penthera.swift +6 -7
- package/ios/Penthera.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
- package/ios/Penthera.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
- package/ios/Penthera.xcodeproj/project.xcworkspace/xcuserdata/joseguerreroot.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/ios/Penthera.xcodeproj/xcuserdata/joseguerreroot.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +104 -0
- package/ios/Penthera.xcodeproj/xcuserdata/joseguerreroot.xcuserdatad/xcschemes/xcschememanagement.plist +14 -0
- package/lib/commonjs/hooks/usePenthera/index.js +28 -0
- package/lib/commonjs/hooks/usePenthera/index.js.map +1 -0
- package/lib/commonjs/hooks/usePenthera/usePenthera.js +184 -0
- package/lib/commonjs/hooks/usePenthera/usePenthera.js.map +1 -0
- package/lib/commonjs/{utils/Penthera.js → hooks/usePenthera/usePenthera.types.js} +1 -1
- package/lib/commonjs/hooks/usePenthera/usePenthera.types.js.map +1 -0
- package/lib/commonjs/index.js +11 -19
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/nativeModules/index.js +7 -2
- package/lib/commonjs/nativeModules/index.js.map +1 -1
- package/lib/module/hooks/usePenthera/index.js +3 -0
- package/lib/module/hooks/usePenthera/index.js.map +1 -0
- package/lib/module/hooks/usePenthera/usePenthera.js +176 -0
- package/lib/module/hooks/usePenthera/usePenthera.js.map +1 -0
- package/lib/module/{utils/Penthera.js → hooks/usePenthera/usePenthera.types.js} +1 -1
- package/lib/module/hooks/usePenthera/usePenthera.types.js.map +1 -0
- package/lib/module/index.js +1 -3
- package/lib/module/index.js.map +1 -1
- package/lib/module/nativeModules/index.js +7 -2
- package/lib/module/nativeModules/index.js.map +1 -1
- package/lib/typescript/hooks/usePenthera/index.d.ts +3 -0
- package/lib/typescript/hooks/usePenthera/index.d.ts.map +1 -0
- package/lib/typescript/hooks/usePenthera/usePenthera.d.ts +4 -0
- package/lib/typescript/hooks/usePenthera/usePenthera.d.ts.map +1 -0
- package/lib/typescript/hooks/usePenthera/usePenthera.types.d.ts +44 -0
- package/lib/typescript/hooks/usePenthera/usePenthera.types.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +1 -2
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/interface/PentheraTypes.d.ts +6 -0
- package/lib/typescript/interface/PentheraTypes.d.ts.map +1 -1
- package/lib/typescript/nativeModules/index.d.ts +1 -1
- package/lib/typescript/nativeModules/index.d.ts.map +1 -1
- package/package.json +4 -1
- package/src/hooks/usePenthera/index.ts +2 -0
- package/src/hooks/usePenthera/usePenthera.tsx +209 -0
- package/src/hooks/usePenthera/usePenthera.types.ts +46 -0
- package/src/index.tsx +1 -3
- package/src/interface/PentheraTypes.ts +7 -0
- package/src/nativeModules/index.ts +16 -9
- package/lib/commonjs/hooks/index.js +0 -13
- package/lib/commonjs/hooks/index.js.map +0 -1
- package/lib/commonjs/hooks/usePenthera.js +0 -147
- package/lib/commonjs/hooks/usePenthera.js.map +0 -1
- package/lib/commonjs/utils/Penthera.js.map +0 -1
- package/lib/module/hooks/index.js +0 -2
- package/lib/module/hooks/index.js.map +0 -1
- package/lib/module/hooks/usePenthera.js +0 -141
- package/lib/module/hooks/usePenthera.js.map +0 -1
- package/lib/module/utils/Penthera.js.map +0 -1
- package/lib/typescript/hooks/index.d.ts +0 -2
- package/lib/typescript/hooks/index.d.ts.map +0 -1
- package/lib/typescript/hooks/usePenthera.d.ts +0 -21
- package/lib/typescript/hooks/usePenthera.d.ts.map +0 -1
- package/lib/typescript/utils/Penthera.d.ts +0 -12
- package/lib/typescript/utils/Penthera.d.ts.map +0 -1
- package/src/hooks/index.ts +0 -1
- package/src/hooks/usePenthera.ts +0 -156
- package/src/utils/Penthera.ts +0 -11
package/ios/Catalog.swift
CHANGED
|
@@ -20,6 +20,7 @@ struct OfflineCatalog: Codable {
|
|
|
20
20
|
var licenseUrl: String = ""
|
|
21
21
|
var isCompleted: Bool
|
|
22
22
|
var isPaused: Bool
|
|
23
|
+
var percentage: Float?
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
struct Thumbnails: Codable {
|
|
@@ -58,6 +59,7 @@ struct DataItem: Codable {
|
|
|
58
59
|
var isExpired: Bool?
|
|
59
60
|
var inForcedExpire: Bool?
|
|
60
61
|
var effectiveExpiryDate: String?
|
|
62
|
+
|
|
61
63
|
}
|
|
62
64
|
|
|
63
65
|
struct Offers: Codable {
|
|
@@ -0,0 +1,501 @@
|
|
|
1
|
+
import VirtuosoClientDownloadEngine
|
|
2
|
+
|
|
3
|
+
@objc(Penthera)
|
|
4
|
+
class Penthera: RCTEventEmitter, VirtuosoDownloadEngineNotificationsDelegate {
|
|
5
|
+
var downloadEngineNotifications: VirtuosoDownloadEngineNotificationManager!
|
|
6
|
+
|
|
7
|
+
public override init() {
|
|
8
|
+
super.init()
|
|
9
|
+
EventEmitter.sharedInstance.registerEventEmitter(eventEmitter: self)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
var statusDownload: StatusDownload = StatusDownload()
|
|
13
|
+
|
|
14
|
+
@objc(initializeSdk:withBackplaneUrl:withPublicKey:withPrivateKey:withResolver:withRejecter:)
|
|
15
|
+
func initializeSdk(user: String, backplaneUrl: String, publicKey: String, privateKey: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void {
|
|
16
|
+
guard let engineConfig = VirtuosoEngineConfig(
|
|
17
|
+
user: user,
|
|
18
|
+
backplaneUrl: backplaneUrl,
|
|
19
|
+
publicKey: publicKey,
|
|
20
|
+
privateKey: privateKey) else {
|
|
21
|
+
return reject("Penthera", "engine Config", nil)
|
|
22
|
+
}
|
|
23
|
+
self.downloadEngineNotifications = VirtuosoDownloadEngineNotificationManager.init(delegate: self)
|
|
24
|
+
let virtuoso = VirtuosoDownloadEngine.instance()
|
|
25
|
+
virtuoso.startup(engineConfig) { status in
|
|
26
|
+
switch(status) {
|
|
27
|
+
case .vde_EngineStartupSuccess:
|
|
28
|
+
EventEmitter.sharedInstance.dispatch(name: "penthera", code: "Virtuoso Success", assetId: "test", body: "asset")
|
|
29
|
+
resolve("Success")
|
|
30
|
+
case .vde_EngineStartupAlreadyStarted:
|
|
31
|
+
//EventEmitter.sharedInstance.dispatch(name: "penthera", body: "Virtuoso Aready Started")
|
|
32
|
+
resolve("Already Started")
|
|
33
|
+
case .vde_EngineStartupSuccessNoBackplane:
|
|
34
|
+
//EventEmitter.sharedInstance.dispatch(name: "penthera", body: "Virtuoso Backplane")
|
|
35
|
+
resolve("No Backplane")
|
|
36
|
+
case .vde_EngineStartupInvalidOptions:
|
|
37
|
+
//EventEmitter.sharedInstance.dispatch(name: "penthera", body: "Virtuoso Invalid")
|
|
38
|
+
resolve("Invalid Option")
|
|
39
|
+
case .vde_EngineStartupMethodIsDeprecated:
|
|
40
|
+
//EventEmitter.sharedInstance.dispatch(name: "penthera", body: "Virtuoso Method Decraped")
|
|
41
|
+
resolve("Decraped")
|
|
42
|
+
case .vde_EngineStartupInternalException:
|
|
43
|
+
//EventEmitter.sharedInstance.dispatch(name: "penthera", body: "Virtuoso Internal Exception")
|
|
44
|
+
resolve("Internal Exception")
|
|
45
|
+
case .vde_EngineDataMigrationError:
|
|
46
|
+
//EventEmitter.sharedInstance.dispatch(name: "penthera", body: "Virtuoso Migrate Error")
|
|
47
|
+
resolve("Error")
|
|
48
|
+
@unknown default:
|
|
49
|
+
//EventEmitter.sharedInstance.dispatch(name: "penthera", body: "Virtuoso Default")
|
|
50
|
+
resolve("Error Default")
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
func timeIntervalToString(_ timeInterval: TimeInterval?) -> String {
|
|
56
|
+
let formatter = DateComponentsFormatter()
|
|
57
|
+
formatter.allowedUnits = [.hour, .minute, .second]
|
|
58
|
+
formatter.unitsStyle = .positional
|
|
59
|
+
formatter.zeroFormattingBehavior = .pad
|
|
60
|
+
guard let interval = timeInterval else {
|
|
61
|
+
return "00:00:00"
|
|
62
|
+
}
|
|
63
|
+
return formatter.string(from: interval) ?? "00:00:00"
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
func dateToString (_ date: Date?) -> String? {
|
|
67
|
+
let dateFormatter = DateFormatter()
|
|
68
|
+
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
|
|
69
|
+
return date != nil ? dateFormatter.string(from: date!) : nil
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
@objc(getDownloads:withResolver:withRejecter:)
|
|
74
|
+
func getDownloads(blank: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void {
|
|
75
|
+
let completedAssets = VirtuosoAsset.completedAssets(withAvailabilityFilter: false)
|
|
76
|
+
let pendingAssets = VirtuosoAsset.pendingAssets(withAvailabilityFilter: false)
|
|
77
|
+
var offlineCatalogs: [OfflineCatalog] = []
|
|
78
|
+
|
|
79
|
+
for case let va as VirtuosoAsset in completedAssets {
|
|
80
|
+
let thumbnail = va.findAllAncillaries(withTag: "thumbnail").first
|
|
81
|
+
let show = va.findAllAncillaries(withTag: "show").first
|
|
82
|
+
let thumbnails = Thumbnails(
|
|
83
|
+
thumbnail: thumbnail?.fileDownloadURL ?? "",
|
|
84
|
+
show: show?.fileDownloadURL ?? ""
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
let expiryDate = va.expiryDate // Assuming this is a valid Date object
|
|
88
|
+
let effectiveExpiryDate = va.effectiveExpiryDate // Assuming this is a valid Date object
|
|
89
|
+
|
|
90
|
+
let dataItem = DataItem(
|
|
91
|
+
title: va.userInfo?["title"] as? String,
|
|
92
|
+
seasonId: va.userInfo?["seasonId"] as? String,
|
|
93
|
+
seasonTitle: va.userInfo?["seasonTitle"] as? String,
|
|
94
|
+
duration: va.duration,
|
|
95
|
+
estimatedSize: Int(va.estimatedSize),
|
|
96
|
+
dataOffers: parseDataOffer(offer: va.userInfo?["dataOffers"] as Any),
|
|
97
|
+
expiryDate: dateToString(expiryDate),
|
|
98
|
+
expiryAfterPlay: timeIntervalToString(va.expiryAfterPlay),
|
|
99
|
+
expiryAfterDownload: timeIntervalToString(va.expiryAfterDownload),
|
|
100
|
+
isExpired: va.isExpired,
|
|
101
|
+
inForcedExpire: va.inForcedExpire,
|
|
102
|
+
effectiveExpiryDate: dateToString(effectiveExpiryDate!)
|
|
103
|
+
)
|
|
104
|
+
let catalog = OfflineCatalog(
|
|
105
|
+
id: va.assetID,
|
|
106
|
+
title: va.description,
|
|
107
|
+
data: dataItem,
|
|
108
|
+
thumbnails: thumbnails,
|
|
109
|
+
isCompleted: va.isPlayable,
|
|
110
|
+
isPaused: va.isPaused,
|
|
111
|
+
percentage: Float(va.fractionComplete) / Float(va.estimatedSize)
|
|
112
|
+
)
|
|
113
|
+
offlineCatalogs.append(catalog)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
for case let va as VirtuosoAsset in pendingAssets {
|
|
117
|
+
|
|
118
|
+
let thumbnail = va.findAllAncillaries(withTag: "thumbnail").first
|
|
119
|
+
let show = va.findAllAncillaries(withTag: "show").first
|
|
120
|
+
let thumbnails = Thumbnails(
|
|
121
|
+
thumbnail: thumbnail?.fileDownloadURL ?? "",
|
|
122
|
+
show: show?.fileDownloadURL ?? ""
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
let expiryDate = va.expiryDate // Assuming this is a valid Date object
|
|
126
|
+
let effectiveExpiryDate = va.effectiveExpiryDate // Assuming this is a valid Date object
|
|
127
|
+
let dataItem = DataItem(
|
|
128
|
+
title: va.userInfo?["title"] as? String,
|
|
129
|
+
seasonId: va.userInfo?["seasonId"] as? String,
|
|
130
|
+
seasonTitle: va.userInfo?["seasonTitle"] as? String,
|
|
131
|
+
duration: va.duration,
|
|
132
|
+
estimatedSize: Int(va.estimatedSize),
|
|
133
|
+
dataOffers: parseDataOffer(offer: va.userInfo?["dataOffers"] as Any),
|
|
134
|
+
expiryAfterPlay: timeIntervalToString(va.expiryAfterPlay),
|
|
135
|
+
expiryAfterDownload: timeIntervalToString(va.expiryAfterDownload),
|
|
136
|
+
isExpired: va.isExpired
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
let catalog = OfflineCatalog(
|
|
140
|
+
id: va.assetID,
|
|
141
|
+
title: va.description,
|
|
142
|
+
data: dataItem,
|
|
143
|
+
thumbnails: thumbnails,
|
|
144
|
+
isCompleted: false,
|
|
145
|
+
isPaused: va.isPaused,
|
|
146
|
+
percentage: Float(va.fractionComplete) / Float(va.estimatedSize)
|
|
147
|
+
)
|
|
148
|
+
offlineCatalogs.append(catalog)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
let decoder = JSONEncoder()
|
|
152
|
+
do {
|
|
153
|
+
let data = try decoder.encode(offlineCatalogs)
|
|
154
|
+
let json = String(data: data, encoding: .utf8)!
|
|
155
|
+
resolve(json)
|
|
156
|
+
} catch {
|
|
157
|
+
reject("penthere", error.localizedDescription, error)
|
|
158
|
+
}
|
|
159
|
+
//resolve(downloadComplete.map{ ($0 as? VirtuosoAsset)?.assetID })
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
func getDownloadedAsset(assetID: String) -> VirtuosoAsset? {
|
|
163
|
+
// assets that have finished downloading
|
|
164
|
+
let completedAssets = VirtuosoAsset.completedAssets(withAvailabilityFilter: false)
|
|
165
|
+
guard let asset = completedAssets.filter({ ($0 as! VirtuosoAsset).assetID == assetID }).first as? VirtuosoAsset else {
|
|
166
|
+
return nil
|
|
167
|
+
}
|
|
168
|
+
return asset
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
public func downloadEngineDidStartDownloadingAsset(_ asset: VirtuosoAsset) {
|
|
172
|
+
EventEmitter.sharedInstance.dispatch(name: "penthera", code: PentheraEvent.DID_START_DOWNLOADING, assetId: asset.assetID, body: "")
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
public func downloadEngineProgressUpdated(for asset: VirtuosoAsset) {
|
|
176
|
+
let percentage: Float = Float(asset.fractionComplete)/Float(asset.estimatedSize)
|
|
177
|
+
if(percentage.isFinite) {
|
|
178
|
+
EventEmitter.sharedInstance.dispatch(name: "penthera", code: PentheraEvent.PROGRESS_UPDATED, assetId: asset.assetID, body: "\(Int(asset.fractionComplete*100))")
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
public func downloadEngineProgressUpdatedProcessing(for asset: VirtuosoAsset) {
|
|
183
|
+
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
public func downloadEngineDidFinishDownloadingAsset(_ asset: VirtuosoAsset) {
|
|
187
|
+
EventEmitter.sharedInstance.dispatch(name: "penthera", code: PentheraEvent.DOWNLOAD_COMPLETE, assetId: asset.assetID, body: "")
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
public func downloadEngineDidEncounterError(for asset: VirtuosoAsset, error: Error?, task: URLSessionTask?, data: Data?, statusCode: NSNumber?) {
|
|
191
|
+
asset.delete()
|
|
192
|
+
EventEmitter.sharedInstance.dispatch(name: "penthera", code: PentheraEvent.ERROR_DOWNLOAD, assetId: asset.assetID, body: error.debugDescription ?? "Error downloading")
|
|
193
|
+
/*EventEmitter.sharedInstance.dispatch(name: "penthera", body: "\(asset.assetID): Engine did encounter error \(error?.localizedDescription ?? "-")")*/
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
public func downloadEngineInternalQueueUpdate(asset: VirtuosoAsset) {
|
|
197
|
+
//EventEmitter.sharedInstance.dispatch(name: "penthera", code: "TEST downloadEngineInternalQueueUpdate", body: "Queue updated", assetId: asset.assetID)
|
|
198
|
+
EventEmitter.sharedInstance.dispatch(name: "penthera", code: "TEST downloadEngineInternalQueueUpdate", assetId: asset.assetID, body: "Queue updated")
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
public func downloadEngineStartupComplete(_ succeeded: Bool, asset: VirtuosoAsset) {
|
|
202
|
+
//EventEmitter.sharedInstance.dispatch(name: "penthera", code: "Test downloadEngineStartupComplete", body: "SDK startup complete", assetId: asset.assetID)
|
|
203
|
+
EventEmitter.sharedInstance.dispatch(name: "penthera", code: "TEST downloadEngineStartupComplete", assetId: asset.assetID, body: "SDK startup complete")
|
|
204
|
+
}
|
|
205
|
+
func getPendingAsset(assetID: String) -> VirtuosoAsset? {
|
|
206
|
+
let pendingAssets = VirtuosoAsset.pendingAssets(withAvailabilityFilter: false)
|
|
207
|
+
guard let asset = pendingAssets.filter({ ($0 as! VirtuosoAsset).assetID == assetID }).first as? VirtuosoAsset else {
|
|
208
|
+
return nil
|
|
209
|
+
}
|
|
210
|
+
return asset
|
|
211
|
+
}
|
|
212
|
+
func getAncillaryFiles(files: [String: AnyObject]) -> [VirtuosoAncillaryFile] {
|
|
213
|
+
var ancillaryFiles: [VirtuosoAncillaryFile] = []
|
|
214
|
+
files.forEach { file in
|
|
215
|
+
guard let url = file.value as? String else {
|
|
216
|
+
return
|
|
217
|
+
}
|
|
218
|
+
guard let ancillaryFile = VirtuosoAncillaryFile(downloadUrl: url, andTag: file.key) else {
|
|
219
|
+
return
|
|
220
|
+
}
|
|
221
|
+
ancillaryFiles.append(ancillaryFile)
|
|
222
|
+
}
|
|
223
|
+
return ancillaryFiles
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
@objc(download:withResolver:withRejecter:)
|
|
227
|
+
func download(catalogString: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void {
|
|
228
|
+
let virtuoso = VirtuosoDownloadEngine.instance()
|
|
229
|
+
var queue = virtuoso.assetsInQueue()
|
|
230
|
+
|
|
231
|
+
//let decoder = JSONDecoder()
|
|
232
|
+
|
|
233
|
+
do {
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
let data = catalogString.getDictionary()
|
|
237
|
+
|
|
238
|
+
guard let item = data!["item"] as! [String: AnyObject]? else {
|
|
239
|
+
reject("No item", nil, nil)
|
|
240
|
+
return
|
|
241
|
+
}
|
|
242
|
+
guard let url = data!["url"] as? String else {
|
|
243
|
+
reject("No url", nil, nil)
|
|
244
|
+
return
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
let assetID = item["id"] as! String? ?? ""
|
|
248
|
+
let hasDRM = item["drm"] as! Bool? ?? false
|
|
249
|
+
let title = item["title"] as! String? ?? ""
|
|
250
|
+
|
|
251
|
+
let downloadAsset = getDownloadedAsset(assetID: assetID)
|
|
252
|
+
let pendingAsset = getPendingAsset(assetID: assetID)
|
|
253
|
+
|
|
254
|
+
if (pendingAsset != nil) {
|
|
255
|
+
EventEmitter.sharedInstance.dispatch(name: "penthera", code: PentheraEvent.PENDING_ASSET_FOUND, assetId: assetID, body: "")
|
|
256
|
+
pendingAsset?.delete()
|
|
257
|
+
return
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
if(downloadAsset == nil && pendingAsset == nil) {
|
|
261
|
+
DispatchQueue.global(qos: .background).async {
|
|
262
|
+
guard let config = VirtuosoAssetConfig(url: url,
|
|
263
|
+
assetID: assetID,
|
|
264
|
+
description: String(describing: title),
|
|
265
|
+
type: .vde_AssetTypeHLS) else {
|
|
266
|
+
EventEmitter.sharedInstance.dispatch(name: "penthera", code: PentheraEvent.CONFIG_ASSET_FAILED, assetId: assetID, body: "-")
|
|
267
|
+
return
|
|
268
|
+
}
|
|
269
|
+
// Ancillary Files
|
|
270
|
+
let thumbnails = item["thumbnails"] as! [String: AnyObject]? ?? [:]
|
|
271
|
+
let subtitles = item["subtitles"] as! [String: AnyObject]? ?? [:]
|
|
272
|
+
config.ancillaries = self.getAncillaryFiles(files: thumbnails) + self.getAncillaryFiles(files: subtitles)
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
//DRM
|
|
276
|
+
if(hasDRM) {
|
|
277
|
+
|
|
278
|
+
guard let drm = data!["drm"] as! [String: AnyObject]? else {
|
|
279
|
+
reject("No drm", nil, nil)
|
|
280
|
+
return
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
let token = drm["token"] as! String? ?? ""
|
|
284
|
+
let licenceHttpHeader = drm["licence_server_http_header"] as! String? ?? ""
|
|
285
|
+
let licence = drm["licence_server"] as! String? ?? ""
|
|
286
|
+
let cert = drm["fairplay_cert"] as! String? ?? ""
|
|
287
|
+
|
|
288
|
+
guard let drmSetup = FairPlayDrmSetup(assetID: assetID, certificateUrl: cert, licenceUrl: licence, header: licenceHttpHeader, token: token) else {
|
|
289
|
+
EventEmitter.sharedInstance.dispatch(name: "penthera", code: PentheraEvent.FAIR_PLAY_LICENSE_DELEGATE_ERROR, assetId: "", body: "")
|
|
290
|
+
return
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
if !drmSetup.configure() {
|
|
294
|
+
EventEmitter.sharedInstance.dispatch(name: "penthera", code: PentheraEvent.FAIR_PLAY_LICENSE_DELEGATE_ERROR, assetId: "", body: "")
|
|
295
|
+
return
|
|
296
|
+
}
|
|
297
|
+
config.protectionType = .vde_AssetProtectionTypeFairPlay
|
|
298
|
+
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
let asset = VirtuosoAsset.init(config: config)
|
|
302
|
+
|
|
303
|
+
let data = item["data"] as! [String: AnyObject]? ?? [:]
|
|
304
|
+
|
|
305
|
+
asset?.userInfo = data
|
|
306
|
+
|
|
307
|
+
config.ancillaries?.forEach{ file in
|
|
308
|
+
asset?.add(file)
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
//asset?.add(subtitle!)
|
|
313
|
+
|
|
314
|
+
//let calendar = Calendar.current
|
|
315
|
+
//guard let expiryDate = calendar.date(byAdding: .minute, value: 1, to: Date()) else {
|
|
316
|
+
// return
|
|
317
|
+
//}
|
|
318
|
+
|
|
319
|
+
//asset?.expiryAfterDownload = expiryDate.timeIntervalSinceNow
|
|
320
|
+
|
|
321
|
+
queue.append(asset!)
|
|
322
|
+
resolve(assetID)
|
|
323
|
+
//resolve(queue.count)
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
} catch {
|
|
328
|
+
reject("penthera", error.localizedDescription, error)
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
@objc(delete:withResolver:withRejecter:)
|
|
333
|
+
func delete(assetID: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void {
|
|
334
|
+
//DispatchQueue.global(qos: .background).async {
|
|
335
|
+
|
|
336
|
+
let downloadComplete = VirtuosoAsset.completedAssets(withAvailabilityFilter: false)
|
|
337
|
+
if(downloadComplete.count > 0) {
|
|
338
|
+
for case let va as VirtuosoAsset in downloadComplete {
|
|
339
|
+
if(va.assetID == assetID){
|
|
340
|
+
va.delete()
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
//(downloadComplete.first as! VirtuosoAsset).delete()
|
|
344
|
+
}
|
|
345
|
+
resolve("Delete complete")
|
|
346
|
+
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
|
|
347
|
+
EventEmitter.sharedInstance.dispatch(name: "penthera", code: PentheraEvent.ASSET_DELETED, assetId: assetID, body: "")
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
@objc(deleteMany:withResolver:withRejecter:)
|
|
354
|
+
func deleteMany(assetIDS: [String], resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void {
|
|
355
|
+
// initialize assetResponse {}. Ex {"123":false, "543":false}
|
|
356
|
+
var assetsResponse: [String: Bool] = Dictionary(uniqueKeysWithValues: assetIDS.map { ($0, false) })
|
|
357
|
+
|
|
358
|
+
let downloadComplete = VirtuosoAsset.completedAssets(withAvailabilityFilter: false)
|
|
359
|
+
if(downloadComplete.count > 0) {
|
|
360
|
+
var assetsToDelete: [VirtuosoAsset] = []
|
|
361
|
+
for asset in downloadComplete {
|
|
362
|
+
if let va = asset as? VirtuosoAsset, assetIDS.contains(va.assetID) {
|
|
363
|
+
assetsToDelete.append(va)
|
|
364
|
+
assetsResponse[va.assetID] = true
|
|
365
|
+
if assetsToDelete.count == assetIDS.count { // Se encontraron todos los assets, break for.
|
|
366
|
+
break
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
VirtuosoAsset.delete(assetsToDelete) { () in
|
|
373
|
+
resolve(assetsResponse)
|
|
374
|
+
}
|
|
375
|
+
} else {
|
|
376
|
+
// No hay assets completados para eliminar
|
|
377
|
+
let errorMessage = "deleteMany: completedAssets is empty"
|
|
378
|
+
let userInfo = [NSLocalizedDescriptionKey: errorMessage]
|
|
379
|
+
let error = NSError(domain: "takeoffmedia-react-native-penthera", code: 0, userInfo: userInfo)
|
|
380
|
+
reject("ASSET_DELETE_ERROR", errorMessage, error)
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
@objc open override func supportedEvents() -> [String] {
|
|
387
|
+
return EventEmitter.sharedInstance.allEvents
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
@objc(playAsset:withResolver:withRejecter:)
|
|
391
|
+
func playAsset(assetID: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void {
|
|
392
|
+
|
|
393
|
+
let downloadComplete = VirtuosoAsset.completedAssets(withAvailabilityFilter: false)
|
|
394
|
+
guard let asset = downloadComplete.filter({ ($0 as! VirtuosoAsset).assetID == assetID }).first as? VirtuosoAsset else {
|
|
395
|
+
reject("Error streaming asset", "", nil)
|
|
396
|
+
return
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
let decoder = JSONEncoder()
|
|
400
|
+
|
|
401
|
+
do {
|
|
402
|
+
|
|
403
|
+
|
|
404
|
+
// let subtitle = vcHttpServer?.ancillaryURLForAncillary(withTag: "subtitle", usingMime: "text/vtt")
|
|
405
|
+
// let thumbnailOffline = asset.findAllAncillaries(withTag: "thumbnailOffline").first
|
|
406
|
+
//let wallpaper = asset.findAllAncillaries(withTag: "wallpaper").first
|
|
407
|
+
|
|
408
|
+
let vcHttpServer = VirtuosoClientHTTPServer(asset: asset)
|
|
409
|
+
|
|
410
|
+
let licenseURL = vcHttpServer?.fairPlayLicenseServerURL
|
|
411
|
+
let certificateURL = vcHttpServer?.fairPlayCertificateDataURL(forSubType: nil)
|
|
412
|
+
|
|
413
|
+
//let avContentKeySession = VirtuosoLicenseManager.registeredAVContentKeySession()
|
|
414
|
+
|
|
415
|
+
//let userInfoData = try encoder.encode(asset.userInfo)
|
|
416
|
+
//let userInfo = String(data: userInfoData, encoding: .utf8)
|
|
417
|
+
|
|
418
|
+
let assetData = [
|
|
419
|
+
"id": asset.assetID,
|
|
420
|
+
"url": vcHttpServer?.playbackURL ?? "",
|
|
421
|
+
"certificate": certificateURL ,
|
|
422
|
+
"license": licenseURL
|
|
423
|
+
]
|
|
424
|
+
|
|
425
|
+
let data = try decoder.encode(assetData)
|
|
426
|
+
let json = String(data: data, encoding: .utf8)!
|
|
427
|
+
resolve(json)
|
|
428
|
+
|
|
429
|
+
// let config = PlayerConfig()
|
|
430
|
+
// config.styleConfig.userInterfaceType = .system
|
|
431
|
+
// config.key = "ASSSSSS"
|
|
432
|
+
|
|
433
|
+
// let player = PlayerFactory.create(playerConfig: config)
|
|
434
|
+
|
|
435
|
+
// guard let streamUrl = URL(string: vcHttpServer!.playbackURL) else {
|
|
436
|
+
// return
|
|
437
|
+
// }
|
|
438
|
+
|
|
439
|
+
// // Create a SourceConfig
|
|
440
|
+
// let sourceConfig = SourceConfig(url: streamUrl, type: .hls)
|
|
441
|
+
// print(streamUrl.absoluteString)
|
|
442
|
+
|
|
443
|
+
// // Optionally set additional properties
|
|
444
|
+
// sourceConfig.title = "Art of motion"
|
|
445
|
+
|
|
446
|
+
// DispatchQueue.main.async {
|
|
447
|
+
// let source = SourceFactory.create(from: sourceConfig)
|
|
448
|
+
|
|
449
|
+
// player.load(source: source)
|
|
450
|
+
|
|
451
|
+
|
|
452
|
+
// let viewController = UIApplication.shared.windows.first?.rootViewController as? UIViewController
|
|
453
|
+
|
|
454
|
+
// let playerView = PlayerView(player: player, frame: (viewController?.view.bounds)!)
|
|
455
|
+
|
|
456
|
+
// // Adding the view to the a container View
|
|
457
|
+
// viewController?.view.addSubview(playerView)
|
|
458
|
+
// viewController?.view.bringSubviewToFront(playerView)
|
|
459
|
+
// }
|
|
460
|
+
|
|
461
|
+
|
|
462
|
+
/*
|
|
463
|
+
let demoPlayer = DemoPlayerViewController()
|
|
464
|
+
DispatchQueue.main.async {
|
|
465
|
+
asset.play(using: .vde_AssetPlaybackTypeLocal,
|
|
466
|
+
andPlayer: demoPlayer as VirtuosoPlayer,
|
|
467
|
+
onSuccess: {
|
|
468
|
+
// Present the player
|
|
469
|
+
|
|
470
|
+
let viewController = UIApplication.shared.windows.first?.rootViewController as? UIViewController
|
|
471
|
+
viewController?.present(demoPlayer, animated: true)
|
|
472
|
+
//self.present(demoPlayer, animated: true, completion: nil)
|
|
473
|
+
},
|
|
474
|
+
onFail: {
|
|
475
|
+
//self.error = nil
|
|
476
|
+
})
|
|
477
|
+
}*/
|
|
478
|
+
|
|
479
|
+
} catch {
|
|
480
|
+
reject("penthere", error.localizedDescription, error)
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
|
|
485
|
+
@objc(pauseDownload:withResolver:withRejecter:)
|
|
486
|
+
func pauseDownload(assetID: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void {
|
|
487
|
+
let pendingAsset = getPendingAsset(assetID: assetID)
|
|
488
|
+
if (pendingAsset != nil) {
|
|
489
|
+
self.pauseAsset(asset: pendingAsset!)
|
|
490
|
+
return
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
func pauseAsset(asset: VirtuosoAsset) {
|
|
496
|
+
asset.isPaused = !asset.isPaused
|
|
497
|
+
EventEmitter.sharedInstance.dispatch(name: "penthera", code: PentheraEvent.ASSET_RESUME_DOWNLOAD_UPDATED, assetId: asset.assetID, body: "\(asset.isPaused)")
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
|
|
501
|
+
}
|
package/ios/Penthera.m
CHANGED
|
@@ -4,10 +4,6 @@
|
|
|
4
4
|
|
|
5
5
|
@interface RCT_EXTERN_MODULE(Penthera, RCTEventEmitter)
|
|
6
6
|
|
|
7
|
-
RCT_EXTERN_METHOD(multiply:(float)a withB:(float)b
|
|
8
|
-
withResolver:(RCTPromiseResolveBlock)resolve
|
|
9
|
-
withRejecter:(RCTPromiseRejectBlock)reject)
|
|
10
|
-
|
|
11
7
|
RCT_EXTERN_METHOD(initializeSdk:(NSString*)user
|
|
12
8
|
withBackplaneUrl:(NSString*)backplaneUrl
|
|
13
9
|
withPublicKey:(NSString*)publicKey
|
package/ios/Penthera.swift
CHANGED
|
@@ -11,11 +11,6 @@ class Penthera: RCTEventEmitter, VirtuosoDownloadEngineNotificationsDelegate {
|
|
|
11
11
|
|
|
12
12
|
var statusDownload: StatusDownload = StatusDownload()
|
|
13
13
|
|
|
14
|
-
@objc(multiply:withB:withResolver:withRejecter:)
|
|
15
|
-
func multiply(a: Float, b: Float, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
|
|
16
|
-
resolve(a*b)
|
|
17
|
-
}
|
|
18
|
-
|
|
19
14
|
@objc(initializeSdk:withBackplaneUrl:withPublicKey:withPrivateKey:withResolver:withRejecter:)
|
|
20
15
|
func initializeSdk(user: String, backplaneUrl: String, publicKey: String, privateKey: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void {
|
|
21
16
|
guard let engineConfig = VirtuosoEngineConfig(
|
|
@@ -91,6 +86,7 @@ class Penthera: RCTEventEmitter, VirtuosoDownloadEngineNotificationsDelegate {
|
|
|
91
86
|
|
|
92
87
|
let expiryDate = va.expiryDate // Assuming this is a valid Date object
|
|
93
88
|
let effectiveExpiryDate = va.effectiveExpiryDate // Assuming this is a valid Date object
|
|
89
|
+
|
|
94
90
|
let dataItem = DataItem(
|
|
95
91
|
title: va.userInfo?["title"] as? String,
|
|
96
92
|
seasonId: va.userInfo?["seasonId"] as? String,
|
|
@@ -111,7 +107,9 @@ class Penthera: RCTEventEmitter, VirtuosoDownloadEngineNotificationsDelegate {
|
|
|
111
107
|
data: dataItem,
|
|
112
108
|
thumbnails: thumbnails,
|
|
113
109
|
isCompleted: va.isPlayable,
|
|
114
|
-
isPaused: va.isPaused
|
|
110
|
+
isPaused: va.isPaused,
|
|
111
|
+
percentage: Float(va.fractionComplete) / Float(va.estimatedSize)
|
|
112
|
+
)
|
|
115
113
|
offlineCatalogs.append(catalog)
|
|
116
114
|
}
|
|
117
115
|
|
|
@@ -144,7 +142,8 @@ class Penthera: RCTEventEmitter, VirtuosoDownloadEngineNotificationsDelegate {
|
|
|
144
142
|
data: dataItem,
|
|
145
143
|
thumbnails: thumbnails,
|
|
146
144
|
isCompleted: false,
|
|
147
|
-
isPaused: va.isPaused
|
|
145
|
+
isPaused: va.isPaused,
|
|
146
|
+
percentage: Float(va.fractionComplete) / Float(va.estimatedSize)
|
|
148
147
|
)
|
|
149
148
|
offlineCatalogs.append(catalog)
|
|
150
149
|
}
|