@takeoffmedia/react-native-penthera 0.2.17 → 0.2.18
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 +43 -0
- package/ios/Penthera.swift +95 -39
- package/ios/Penthera.xcodeproj/project.xcworkspace/xcuserdata/joseguerreroot.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/ios/Penthera.xcodeproj/xcuserdata/joseguerreroot.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +7 -7
- package/lib/typescript/hooks/usePenthera/usePenthera.types.d.ts +6 -0
- package/lib/typescript/hooks/usePenthera/usePenthera.types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/hooks/usePenthera/usePenthera.types.ts +7 -0
package/ios/Catalog.swift
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
|
|
1
3
|
struct Catalog: Codable {
|
|
2
4
|
var id: String = ""
|
|
3
5
|
var url: String = ""
|
|
@@ -98,3 +100,44 @@ struct Event: Codable {
|
|
|
98
100
|
var assetId: String = ""
|
|
99
101
|
var body: String = ""
|
|
100
102
|
}
|
|
103
|
+
|
|
104
|
+
struct DataInfo: Codable {
|
|
105
|
+
var id: String = ""
|
|
106
|
+
var title: String = ""
|
|
107
|
+
var episodeNumber: Int = 0
|
|
108
|
+
var duration: Int = 0
|
|
109
|
+
var seasonId: String = ""
|
|
110
|
+
var seasonTitle: String = ""
|
|
111
|
+
var dataOffers: [DataOffer] = []
|
|
112
|
+
|
|
113
|
+
struct DataOffer: Codable {
|
|
114
|
+
var bold: Bool = false
|
|
115
|
+
var label: String = ""
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
struct Subtitle: Codable {
|
|
120
|
+
var label: String = ""
|
|
121
|
+
var language: String = ""
|
|
122
|
+
var href: String? = ""
|
|
123
|
+
var url: String? = ""
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
struct DownloadItem: Codable {
|
|
128
|
+
let id: String
|
|
129
|
+
let title: String
|
|
130
|
+
let drm: Bool?
|
|
131
|
+
let path: String?
|
|
132
|
+
let thumbnails: Thumbnails?
|
|
133
|
+
let data: String?
|
|
134
|
+
let subtitles: String
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
struct AssetData: Codable {
|
|
138
|
+
let id: String
|
|
139
|
+
let url: String
|
|
140
|
+
let certificate: String?
|
|
141
|
+
let license: String?
|
|
142
|
+
let subtitles: [Subtitle]?
|
|
143
|
+
}
|
package/ios/Penthera.swift
CHANGED
|
@@ -197,12 +197,10 @@ class Penthera: RCTEventEmitter, VirtuosoDownloadEngineNotificationsDelegate {
|
|
|
197
197
|
}
|
|
198
198
|
return asset
|
|
199
199
|
}
|
|
200
|
-
func getAncillaryFiles(files: [String:
|
|
200
|
+
func getAncillaryFiles(files: [String: String]) -> [VirtuosoAncillaryFile] {
|
|
201
201
|
var ancillaryFiles: [VirtuosoAncillaryFile] = []
|
|
202
202
|
files.forEach { file in
|
|
203
|
-
|
|
204
|
-
return
|
|
205
|
-
}
|
|
203
|
+
let url = file.value
|
|
206
204
|
guard let ancillaryFile = VirtuosoAncillaryFile(downloadUrl: url, andTag: file.key) else {
|
|
207
205
|
return
|
|
208
206
|
}
|
|
@@ -211,6 +209,22 @@ class Penthera: RCTEventEmitter, VirtuosoDownloadEngineNotificationsDelegate {
|
|
|
211
209
|
return ancillaryFiles
|
|
212
210
|
}
|
|
213
211
|
|
|
212
|
+
// Función para convertir un String en un objeto DataInfo
|
|
213
|
+
func stringToSubtitles(_ jsonString: String) -> [Subtitle]? {
|
|
214
|
+
// Crear un Data a partir del String
|
|
215
|
+
if let jsonData = jsonString.data(using: .utf8) {
|
|
216
|
+
do {
|
|
217
|
+
// Decodificar el Data en un objeto DataInfo
|
|
218
|
+
let dataInfo = try JSONDecoder().decode([Subtitle].self, from: jsonData)
|
|
219
|
+
return dataInfo
|
|
220
|
+
} catch {
|
|
221
|
+
print("Error al decodificar el String en Subtitle: \(error)")
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
return nil
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
|
|
214
228
|
@objc(download:withResolver:withRejecter:)
|
|
215
229
|
func download(catalogString: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) -> Void {
|
|
216
230
|
let virtuoso = VirtuosoDownloadEngine.instance()
|
|
@@ -232,6 +246,7 @@ class Penthera: RCTEventEmitter, VirtuosoDownloadEngineNotificationsDelegate {
|
|
|
232
246
|
return
|
|
233
247
|
}
|
|
234
248
|
|
|
249
|
+
|
|
235
250
|
let assetID = item["id"] as! String? ?? ""
|
|
236
251
|
|
|
237
252
|
let hasDRM = item["drm"] as! Bool? ?? false
|
|
@@ -247,41 +262,56 @@ class Penthera: RCTEventEmitter, VirtuosoDownloadEngineNotificationsDelegate {
|
|
|
247
262
|
}
|
|
248
263
|
// Ancillary Files
|
|
249
264
|
let thumbnails = item["thumbnails"] as! [String: AnyObject]? ?? [:]
|
|
250
|
-
let
|
|
251
|
-
|
|
252
|
-
|
|
265
|
+
if let subtitlesString = item["subtitles"] as? String {
|
|
266
|
+
if let subtitles = self.stringToSubtitles(subtitlesString) {
|
|
267
|
+
var ancillarySubtitles: [String: String] = [:]
|
|
268
|
+
|
|
269
|
+
for subtitle in subtitles {
|
|
270
|
+
ancillarySubtitles[subtitle.language] = subtitle.href;
|
|
271
|
+
}
|
|
272
|
+
config.ancillaries = self.getAncillaryFiles(files: ancillarySubtitles)
|
|
273
|
+
}
|
|
274
|
+
}
|
|
253
275
|
|
|
254
276
|
//DRM
|
|
255
|
-
if(hasDRM) {
|
|
256
277
|
|
|
257
|
-
|
|
258
|
-
reject("No drm", nil, nil)
|
|
259
|
-
return
|
|
260
|
-
}
|
|
278
|
+
if(hasDRM) {
|
|
261
279
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
280
|
+
guard let drm = data!["drm"] as! [String: AnyObject]? else {
|
|
281
|
+
reject("No drm", nil, nil)
|
|
282
|
+
return
|
|
283
|
+
}
|
|
266
284
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
285
|
+
let token = drm["token"] as! String? ?? ""
|
|
286
|
+
let licenceHttpHeader = drm["licence_server_http_header"] as! String? ?? ""
|
|
287
|
+
let licence = drm["licence_server"] as! String? ?? ""
|
|
288
|
+
let cert = drm["fairplay_cert"] as! String? ?? ""
|
|
289
|
+
|
|
290
|
+
guard let drmSetup = FairPlayDrmSetup(assetID: assetID, certificateUrl: cert, licenceUrl: licence, header: licenceHttpHeader, token: token) else {
|
|
291
|
+
EventEmitter.sharedInstance.dispatch(name: "penthera", code: PentheraEvent.FAIR_PLAY_LICENSE_DELEGATE_ERROR, assetId: "", body: "")
|
|
292
|
+
return
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
if !drmSetup.configure() {
|
|
296
|
+
EventEmitter.sharedInstance.dispatch(name: "penthera", code: PentheraEvent.FAIR_PLAY_LICENSE_DELEGATE_ERROR, assetId: "", body: "")
|
|
297
|
+
return
|
|
298
|
+
}
|
|
299
|
+
config.protectionType = .vde_AssetProtectionTypeFairPlay
|
|
271
300
|
|
|
272
|
-
if !drmSetup.configure() {
|
|
273
|
-
EventEmitter.sharedInstance.dispatch(name: "penthera", code: PentheraEvent.FAIR_PLAY_LICENSE_DELEGATE_ERROR, assetId: "", body: "")
|
|
274
|
-
return
|
|
275
301
|
}
|
|
276
|
-
config.protectionType = .vde_AssetProtectionTypeFairPlay
|
|
277
302
|
|
|
278
|
-
}
|
|
279
303
|
|
|
280
304
|
let asset = VirtuosoAsset.init(config: config)
|
|
305
|
+
let data = item["data"]
|
|
306
|
+
|
|
307
|
+
if let dataInfoDict = data as? [AnyHashable: Any] {
|
|
308
|
+
asset?.userInfo = dataInfoDict
|
|
309
|
+
} else {
|
|
310
|
+
asset?.userInfo = nil
|
|
311
|
+
}
|
|
312
|
+
|
|
281
313
|
|
|
282
|
-
let data = item["data"] as! [String: AnyObject]? ?? [:]
|
|
283
314
|
|
|
284
|
-
asset?.userInfo = data
|
|
285
315
|
|
|
286
316
|
config.ancillaries?.forEach{ file in
|
|
287
317
|
asset?.add(file)
|
|
@@ -290,10 +320,6 @@ class Penthera: RCTEventEmitter, VirtuosoDownloadEngineNotificationsDelegate {
|
|
|
290
320
|
queue.append(asset!)
|
|
291
321
|
resolve(assetID)
|
|
292
322
|
}
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
} catch {
|
|
296
|
-
reject("penthera", error.localizedDescription, error)
|
|
297
323
|
}
|
|
298
324
|
}
|
|
299
325
|
|
|
@@ -427,15 +453,46 @@ class Penthera: RCTEventEmitter, VirtuosoDownloadEngineNotificationsDelegate {
|
|
|
427
453
|
|
|
428
454
|
let licenseURL = vcHttpServer?.fairPlayLicenseServerURL
|
|
429
455
|
let certificateURL = vcHttpServer?.fairPlayCertificateDataURL(forSubType: nil)
|
|
456
|
+
var subtitlesResponse: [Subtitle] = []
|
|
457
|
+
var language: String? = nil, url: String? = nil, label: String? = nil
|
|
458
|
+
asset.userInfo.map{ userInfo in
|
|
459
|
+
if let subtitles = userInfo["subtitles"] as? Array<Dictionary<String, String>> {
|
|
460
|
+
for subtitle in subtitles {
|
|
461
|
+
for (key, value) in subtitle {
|
|
462
|
+
if key == "language" {
|
|
463
|
+
url = vcHttpServer?.ancillaryURLForAncillary(withTag: value, usingMime: "")
|
|
464
|
+
language = value
|
|
465
|
+
}
|
|
466
|
+
if key == "label" {
|
|
467
|
+
label = value
|
|
468
|
+
}
|
|
469
|
+
if(label != nil && language != nil && url != nil){
|
|
470
|
+
subtitlesResponse.append(
|
|
471
|
+
Subtitle(
|
|
472
|
+
label: label ?? "",
|
|
473
|
+
language: language ?? "",
|
|
474
|
+
url: url
|
|
475
|
+
)
|
|
476
|
+
)
|
|
477
|
+
label = nil
|
|
478
|
+
language = nil
|
|
479
|
+
url = nil
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
let assetDataObject = AssetData(
|
|
487
|
+
id: asset.assetID,
|
|
488
|
+
url: vcHttpServer?.playbackURL ?? "",
|
|
489
|
+
certificate: certificateURL,
|
|
490
|
+
license: licenseURL,
|
|
491
|
+
subtitles: subtitlesResponse
|
|
492
|
+
)
|
|
430
493
|
|
|
431
|
-
let assetData = [
|
|
432
|
-
"id": asset.assetID,
|
|
433
|
-
"url": vcHttpServer?.playbackURL ?? "",
|
|
434
|
-
"certificate": certificateURL ,
|
|
435
|
-
"license": licenseURL
|
|
436
|
-
]
|
|
437
494
|
|
|
438
|
-
let data = try decoder.encode(
|
|
495
|
+
let data = try decoder.encode(assetDataObject)
|
|
439
496
|
let json = String(data: data, encoding: .utf8)!
|
|
440
497
|
resolve(json)
|
|
441
498
|
|
|
@@ -460,5 +517,4 @@ class Penthera: RCTEventEmitter, VirtuosoDownloadEngineNotificationsDelegate {
|
|
|
460
517
|
EventEmitter.sharedInstance.dispatch(name: "penthera", code: PentheraEvent.ASSET_RESUME_DOWNLOAD_UPDATED, assetId: asset.assetID, body: "\(asset.isPaused)")
|
|
461
518
|
}
|
|
462
519
|
|
|
463
|
-
|
|
464
520
|
}
|
|
Binary file
|
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
endingColumnNumber = "9223372036854775807"
|
|
17
17
|
startingLineNumber = "18"
|
|
18
18
|
endingLineNumber = "18"
|
|
19
|
-
landmarkName = "
|
|
20
|
-
landmarkType = "
|
|
19
|
+
landmarkName = "Penthera"
|
|
20
|
+
landmarkType = "3">
|
|
21
21
|
</BreakpointContent>
|
|
22
22
|
</BreakpointProxy>
|
|
23
23
|
<BreakpointProxy
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
endingColumnNumber = "9223372036854775807"
|
|
33
33
|
startingLineNumber = "25"
|
|
34
34
|
endingLineNumber = "25"
|
|
35
|
-
landmarkName = "
|
|
35
|
+
landmarkName = "updateStatusInfo()"
|
|
36
36
|
landmarkType = "7">
|
|
37
37
|
</BreakpointContent>
|
|
38
38
|
</BreakpointProxy>
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
endingColumnNumber = "9223372036854775807"
|
|
49
49
|
startingLineNumber = "26"
|
|
50
50
|
endingLineNumber = "26"
|
|
51
|
-
landmarkName = "
|
|
51
|
+
landmarkName = "updateStatusInfo()"
|
|
52
52
|
landmarkType = "7">
|
|
53
53
|
</BreakpointContent>
|
|
54
54
|
</BreakpointProxy>
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
endingColumnNumber = "9223372036854775807"
|
|
65
65
|
startingLineNumber = "101"
|
|
66
66
|
endingLineNumber = "101"
|
|
67
|
-
landmarkName = "
|
|
67
|
+
landmarkName = "initializeSdk(user:backplaneUrl:publicKey:privateKey:resolve:reject:)"
|
|
68
68
|
landmarkType = "7">
|
|
69
69
|
</BreakpointContent>
|
|
70
70
|
</BreakpointProxy>
|
|
@@ -80,7 +80,7 @@
|
|
|
80
80
|
endingColumnNumber = "9223372036854775807"
|
|
81
81
|
startingLineNumber = "149"
|
|
82
82
|
endingLineNumber = "149"
|
|
83
|
-
landmarkName = "
|
|
83
|
+
landmarkName = "getDownloadedAsset(assetID:)"
|
|
84
84
|
landmarkType = "7">
|
|
85
85
|
</BreakpointContent>
|
|
86
86
|
</BreakpointProxy>
|
|
@@ -96,7 +96,7 @@
|
|
|
96
96
|
endingColumnNumber = "9223372036854775807"
|
|
97
97
|
startingLineNumber = "148"
|
|
98
98
|
endingLineNumber = "148"
|
|
99
|
-
landmarkName = "
|
|
99
|
+
landmarkName = "getDownloadedAsset(assetID:)"
|
|
100
100
|
landmarkType = "7">
|
|
101
101
|
</BreakpointContent>
|
|
102
102
|
</BreakpointProxy>
|
|
@@ -16,11 +16,17 @@ type Progress = string;
|
|
|
16
16
|
export type AssetProgress = {
|
|
17
17
|
[key: string]: Progress;
|
|
18
18
|
};
|
|
19
|
+
export type Subtitle = {
|
|
20
|
+
url: string;
|
|
21
|
+
label: string;
|
|
22
|
+
language: string;
|
|
23
|
+
};
|
|
19
24
|
export interface InterfaceDataPlay {
|
|
20
25
|
url?: string;
|
|
21
26
|
license?: string;
|
|
22
27
|
certificate?: string;
|
|
23
28
|
id?: string;
|
|
29
|
+
subtitles?: Subtitle[];
|
|
24
30
|
}
|
|
25
31
|
export type PentheraState = {
|
|
26
32
|
assets: PentheraTypes.ItemCatalog[] | [];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usePenthera.types.d.ts","sourceRoot":"","sources":["../../../../src/hooks/usePenthera/usePenthera.types.ts"],"names":[],"mappings":";AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAEjE,oBAAY,aAAa;IACvB,gBAAgB,qBAAqB;IACrC,qBAAqB,0BAA0B;IAC/C,gBAAgB,qBAAqB;IACrC,iBAAiB,sBAAsB;IACvC,mBAAmB,wBAAwB;IAC3C,6BAA6B,kCAAkC;IAC/D,aAAa,kBAAkB;IAC/B,cAAc,mBAAmB;IACjC,mBAAmB,wBAAwB;CAC5C;AACD,MAAM,MAAM,OAAO,GAAG,MAAM,CAAC;AAC7B,KAAK,QAAQ,GAAG,MAAM,CAAC;AAEvB,MAAM,MAAM,aAAa,GAAG;IAC1B,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,CAAC;CACzB,CAAC;AAEF,MAAM,WAAW,iBAAiB;IAChC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,EAAE,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"usePenthera.types.d.ts","sourceRoot":"","sources":["../../../../src/hooks/usePenthera/usePenthera.types.ts"],"names":[],"mappings":";AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAEjE,oBAAY,aAAa;IACvB,gBAAgB,qBAAqB;IACrC,qBAAqB,0BAA0B;IAC/C,gBAAgB,qBAAqB;IACrC,iBAAiB,sBAAsB;IACvC,mBAAmB,wBAAwB;IAC3C,6BAA6B,kCAAkC;IAC/D,aAAa,kBAAkB;IAC/B,cAAc,mBAAmB;IACjC,mBAAmB,wBAAwB;CAC5C;AACD,MAAM,MAAM,OAAO,GAAG,MAAM,CAAC;AAC7B,KAAK,QAAQ,GAAG,MAAM,CAAC;AAEvB,MAAM,MAAM,aAAa,GAAG;IAC1B,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,WAAW,iBAAiB;IAChC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,QAAQ,EAAE,CAAC;CACxB;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,EAAE,aAAa,CAAC,WAAW,EAAE,GAAG,EAAE,CAAC;IACzC,cAAc,EAAE,aAAa,GAAG,EAAE,CAAC;IACnC,UAAU,EAAE,UAAU,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG,KAAK,CAAC,iBAAiB,CAAC;IAC1D,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,qBAAqB,EAAE,MAAM,CAAC;CAC/B,CAAC,CAAC;AAEH,MAAM,MAAM,UAAU,GAAG;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,UAAU,EAAE,CAAC,MAAM,EAAE,aAAa,CAAC,WAAW,EAAE,KAAK,IAAI,CAAC;IAC1D,QAAQ,EAAE,CAAC,KAAK,EAAE,aAAa,CAAC,WAAW,KAAK,IAAI,CAAC;IACrD,gBAAgB,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAC/C,oBAAoB,EAAE,CAAC,aAAa,EAAE,aAAa,KAAK,IAAI,CAAC;IAC7D,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,UAAU,EAAE,CAAC,IAAI,EAAE,aAAa,CAAC,cAAc,KAAK,IAAI,CAAC;IACzD,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACvC,eAAe,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C,WAAW,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAC7D,QAAQ,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,IAAI,CAAC;IACrC,mBAAmB,EAAE,CAAC,IAAI,EAAE,aAAa,CAAC,iBAAiB,KAAK,IAAI,CAAC;CACtE,CAAC;AAEF,MAAM,MAAM,KAAK,GAAG;IAClB,IAAI,EAAE,aAAa,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC"}
|
package/package.json
CHANGED
|
@@ -18,11 +18,18 @@ export type AssetProgress = {
|
|
|
18
18
|
[key: string]: Progress;
|
|
19
19
|
};
|
|
20
20
|
|
|
21
|
+
export type Subtitle = {
|
|
22
|
+
url: string;
|
|
23
|
+
label: string;
|
|
24
|
+
language: string;
|
|
25
|
+
};
|
|
26
|
+
|
|
21
27
|
export interface InterfaceDataPlay {
|
|
22
28
|
url?: string;
|
|
23
29
|
license?: string;
|
|
24
30
|
certificate?: string;
|
|
25
31
|
id?: string;
|
|
32
|
+
subtitles?: Subtitle[];
|
|
26
33
|
}
|
|
27
34
|
|
|
28
35
|
export type PentheraState = {
|