react-native-theoplayer 1.6.0 → 1.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ios/THEOplayerRCTDebug.swift +3 -0
- package/ios/THEOplayerRCTSourceDescriptionBuilder.swift +212 -0
- package/ios/THEOplayerRCTView.swift +6 -7
- package/ios/THEOplayerRCTViewEventHandler.swift +1 -1
- package/lib/typescript/src/__tests__/index.test.d.ts +1 -0
- package/package.json +1 -12
- package/src/__tests__/index.test.tsx +1 -0
|
@@ -14,3 +14,6 @@ let DEBUG_THEOPLAYER_INTERACTION = DEBUG && true
|
|
|
14
14
|
|
|
15
15
|
// Debug flag to monitor all updates made on bridged properties
|
|
16
16
|
let DEBUG_PROP_UPDATES = DEBUG && true
|
|
17
|
+
|
|
18
|
+
// Debug flag to monitor correct SourceDescription buildup
|
|
19
|
+
let DEBUG_SOURCE_DESCRIPTION_BUIDER = DEBUG && true
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
// THEOplayerRCTSourceDescriptionBuilder.swift
|
|
2
|
+
|
|
3
|
+
import Foundation
|
|
4
|
+
import THEOplayerSDK
|
|
5
|
+
import UIKit
|
|
6
|
+
|
|
7
|
+
let SD_PROP_SOURCES: String = "sources"
|
|
8
|
+
let SD_PROP_POSTER: String = "poster"
|
|
9
|
+
let SD_PROP_TEXTTRACKS: String = "textTracks"
|
|
10
|
+
let SD_PROP_SRC: String = "src"
|
|
11
|
+
let SD_PROP_TYPE: String = "type"
|
|
12
|
+
let SD_PROP_INTEGRATION: String = "integration"
|
|
13
|
+
let SD_PROP_SRC_LANG: String = "srclang"
|
|
14
|
+
let SD_PROP_DEFAULT: String = "default"
|
|
15
|
+
let SD_PROP_LABEL: String = "label"
|
|
16
|
+
let SD_PROP_KIND: String = "kind"
|
|
17
|
+
let SD_PROP_FORMAT: String = "format"
|
|
18
|
+
let SD_PROP_CONTENT_PROTECTION: String = "contentProtection"
|
|
19
|
+
|
|
20
|
+
let EXTENSION_HLS: String = ".m3u8"
|
|
21
|
+
let EXTENSION_MP4: String = ".mp4"
|
|
22
|
+
let EXTENSION_MP3: String = ".mp3"
|
|
23
|
+
|
|
24
|
+
let MIMETYPE_HLS = "application/x-mpegurl"
|
|
25
|
+
let MIMETYPE_MP4 = "video/mp4"
|
|
26
|
+
let MIMETYPE_MP3 = "audio/mpeg"
|
|
27
|
+
|
|
28
|
+
let DRM_INTEGRATION_ID_EZDRM = "ezdrm"
|
|
29
|
+
let DRM_INTEGRATION_ID_KEYOS = "keyos"
|
|
30
|
+
let DRM_INTEGRATION_ID_VERIMATRIX = "verimatrix"
|
|
31
|
+
|
|
32
|
+
class THEOplayerRCTSourceDescriptionBuilder {
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
Builds a THEOplayer SourceDescription that can be passed as a source for the THEOplayer.
|
|
36
|
+
- returns: a THEOplayer TypedSource. In case of SSAI we support GoogleDAITypedSource with GoogleDAIVodConfiguration or GoogleDAILiveConfiguration
|
|
37
|
+
*/
|
|
38
|
+
static func buildSourceDescription(_ sourceData: NSDictionary) -> SourceDescription? {
|
|
39
|
+
// 1. Extract "sources"
|
|
40
|
+
guard let sourcesData = sourceData[SD_PROP_SOURCES] else {
|
|
41
|
+
return nil
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
var typedSources: [TypedSource] = []
|
|
45
|
+
// case: array of source objects
|
|
46
|
+
if let sourcesDataArray = sourcesData as? [[String:Any]] {
|
|
47
|
+
for typedSourceData in sourcesDataArray {
|
|
48
|
+
if let typedSource = THEOplayerRCTSourceDescriptionBuilder.buildTypedSource(typedSourceData) {
|
|
49
|
+
typedSources.append(typedSource)
|
|
50
|
+
} else {
|
|
51
|
+
if DEBUG_SOURCE_DESCRIPTION_BUIDER {
|
|
52
|
+
print("[NATIVE] Could not create THEOplayer TypedSource from sourceData array")
|
|
53
|
+
}
|
|
54
|
+
return nil
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
// case: single source object
|
|
59
|
+
else if let typedSourceData = sourcesData as? [String:Any] {
|
|
60
|
+
if let typedSource = THEOplayerRCTSourceDescriptionBuilder.buildTypedSource(typedSourceData) {
|
|
61
|
+
typedSources.append(typedSource)
|
|
62
|
+
} else {
|
|
63
|
+
if DEBUG_SOURCE_DESCRIPTION_BUIDER {
|
|
64
|
+
print("[NATIVE] Could not create THEOplayer TypedSource from sourceData")
|
|
65
|
+
}
|
|
66
|
+
return nil
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// 2. extract 'poster'
|
|
71
|
+
let poster = sourceData[SD_PROP_POSTER] as? String
|
|
72
|
+
|
|
73
|
+
// 3. extract 'textTracks'
|
|
74
|
+
var textTrackDescriptions: [TextTrackDescription]?
|
|
75
|
+
if let textTracksDataArray = sourceData[SD_PROP_TEXTTRACKS] as? [[String:Any]] {
|
|
76
|
+
textTrackDescriptions = []
|
|
77
|
+
for textTracksData in textTracksDataArray {
|
|
78
|
+
if let textTrackDescription = THEOplayerRCTSourceDescriptionBuilder.buildTextTrackDescriptions(textTracksData) {
|
|
79
|
+
textTrackDescriptions?.append(textTrackDescription)
|
|
80
|
+
} else {
|
|
81
|
+
if DEBUG_SOURCE_DESCRIPTION_BUIDER {
|
|
82
|
+
print("[NATIVE] Could not create THEOplayer TextTrackDescription from textTrackData array")
|
|
83
|
+
}
|
|
84
|
+
return nil
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// 4. construct and return SourceDescription
|
|
91
|
+
return SourceDescription(sources: typedSources,
|
|
92
|
+
textTracks: textTrackDescriptions,
|
|
93
|
+
poster: poster,
|
|
94
|
+
metadata: nil) // TODO
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// MARK: Private build methods
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
Creates a THEOplayer TypedSource. This requires a source property for non SSAI strreams (either as a string or as an object contiaining a src property). For SSAI streams the TypeSource can be created from the ssai property.
|
|
101
|
+
- returns: a THEOplayer TypedSource. In case of SSAI we support GoogleDAITypedSource with GoogleDAIVodConfiguration or GoogleDAILiveConfiguration
|
|
102
|
+
*/
|
|
103
|
+
private static func buildTypedSource(_ typedSourceData: [String:Any]) -> TypedSource? {
|
|
104
|
+
if let src = typedSourceData[SD_PROP_SRC] as? String {
|
|
105
|
+
// extract the type
|
|
106
|
+
let type = typedSourceData[SD_PROP_TYPE] as? String ?? THEOplayerRCTSourceDescriptionBuilder.extractMimeType(src)
|
|
107
|
+
// check for a contentProtection
|
|
108
|
+
var contentProtection: MultiplatformDRMConfiguration?
|
|
109
|
+
if let contentProtectionData = typedSourceData[SD_PROP_CONTENT_PROTECTION] as? [String:Any] {
|
|
110
|
+
contentProtection = THEOplayerRCTSourceDescriptionBuilder.buildContentProtection(contentProtectionData)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return TypedSource(src: src,
|
|
114
|
+
type: type,
|
|
115
|
+
drm: contentProtection)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if DEBUG_SOURCE_DESCRIPTION_BUIDER {
|
|
119
|
+
print("[NATIVE] THEOplayer TypedSource requires 'src' property in 'sources' description")
|
|
120
|
+
}
|
|
121
|
+
return nil
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
Creates a THEOplayer TextTrackDescription. This requires a textTracks property in the RN source description.
|
|
126
|
+
- returns: a THEOplayer TextTrackDescription
|
|
127
|
+
*/
|
|
128
|
+
private static func buildTextTrackDescriptions(_ textTracksData: [String:Any]) -> TextTrackDescription? {
|
|
129
|
+
if let textTrackSrc = textTracksData[SD_PROP_SRC] as? String,
|
|
130
|
+
let textTrackSrcLang = textTracksData[SD_PROP_SRC_LANG] as? String {
|
|
131
|
+
let textTrackIsDefault = textTracksData[SD_PROP_DEFAULT] as? Bool
|
|
132
|
+
let textTrackLabel = textTracksData[SD_PROP_LABEL] as? String
|
|
133
|
+
let textTrackKind = THEOplayerRCTSourceDescriptionBuilder.extractTextTrackKind(textTracksData[SD_PROP_KIND] as? String)
|
|
134
|
+
let textTrackFormat = THEOplayerRCTSourceDescriptionBuilder.extractTextTrackFormat(textTracksData[SD_PROP_FORMAT] as? String)
|
|
135
|
+
print(textTrackKind._rawValue)
|
|
136
|
+
print(textTrackFormat._rawValue)
|
|
137
|
+
return TextTrackDescription(src: textTrackSrc,
|
|
138
|
+
srclang: textTrackSrcLang,
|
|
139
|
+
isDefault: textTrackIsDefault,
|
|
140
|
+
kind: textTrackKind,
|
|
141
|
+
label: textTrackLabel,
|
|
142
|
+
format: textTrackFormat)
|
|
143
|
+
}
|
|
144
|
+
return nil
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
Creates a THEOplayer DRMConfiguration. This requires a contentProtection property in the RN source description.
|
|
149
|
+
- returns: a THEOplayer DRMConfiguration
|
|
150
|
+
*/
|
|
151
|
+
private static func buildContentProtection(_ contentProtectionData: [String:Any]) -> MultiplatformDRMConfiguration? {
|
|
152
|
+
do {
|
|
153
|
+
let data = try JSONSerialization.data(withJSONObject: contentProtectionData)
|
|
154
|
+
if let integration = contentProtectionData[SD_PROP_INTEGRATION] as? String {
|
|
155
|
+
switch integration {
|
|
156
|
+
case DRM_INTEGRATION_ID_EZDRM: return try JSONDecoder().decode(EzdrmDRMConfiguration.self, from: data)
|
|
157
|
+
case DRM_INTEGRATION_ID_KEYOS: return try JSONDecoder().decode(KeyOSDRMConfiguration.self, from: data)
|
|
158
|
+
case DRM_INTEGRATION_ID_VERIMATRIX: return try JSONDecoder().decode(VerimatrixDRMConfiguration.self, from: data)
|
|
159
|
+
default: print("[NATIVE] \(integration): unsupported drm integration")
|
|
160
|
+
}
|
|
161
|
+
} else {
|
|
162
|
+
print("[NATIVE] integration type not specified... trying default drm integration")
|
|
163
|
+
return try JSONDecoder().decode(MultiplatformDRMConfiguration.self, from: data)
|
|
164
|
+
}
|
|
165
|
+
} catch {
|
|
166
|
+
print("[NATIVE] unsupported contentProtection data format")
|
|
167
|
+
}
|
|
168
|
+
return nil
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
// MARK: Helper methods
|
|
173
|
+
|
|
174
|
+
private static func extractMimeType(_ src: String) -> String {
|
|
175
|
+
if src.suffix(5) == EXTENSION_HLS {
|
|
176
|
+
return MIMETYPE_HLS
|
|
177
|
+
} else if src.suffix(4) == EXTENSION_MP4 {
|
|
178
|
+
return MIMETYPE_MP4
|
|
179
|
+
} else if src.suffix(4) == EXTENSION_MP3 {
|
|
180
|
+
return MIMETYPE_MP3
|
|
181
|
+
}
|
|
182
|
+
return MIMETYPE_HLS
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
private static func extractTextTrackKind(_ kindString: String?) -> THEOplayerSDK.TextTrackKind {
|
|
186
|
+
guard let kind = kindString else {
|
|
187
|
+
return THEOplayerSDK.TextTrackKind.none
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
switch kind {
|
|
191
|
+
case "subtitles": return THEOplayerSDK.TextTrackKind.subtitles
|
|
192
|
+
case "captions": return THEOplayerSDK.TextTrackKind.captions
|
|
193
|
+
case "description": return THEOplayerSDK.TextTrackKind.description
|
|
194
|
+
case "chapters": return THEOplayerSDK.TextTrackKind.chapters
|
|
195
|
+
case "metadata": return THEOplayerSDK.TextTrackKind.metadata
|
|
196
|
+
default: return THEOplayerSDK.TextTrackKind.none
|
|
197
|
+
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
private static func extractTextTrackFormat(_ formatString: String?) -> THEOplayerSDK.TextTrackFormat {
|
|
202
|
+
guard let format = formatString else {
|
|
203
|
+
return THEOplayerSDK.TextTrackFormat.none
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if format == "webvtt" {
|
|
207
|
+
return THEOplayerSDK.TextTrackFormat.WebVTT
|
|
208
|
+
} else {
|
|
209
|
+
return THEOplayerSDK.TextTrackFormat.none
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
@@ -70,14 +70,13 @@ class THEOplayerRCTView: UIView {
|
|
|
70
70
|
// MARK: - Property bridging
|
|
71
71
|
@objc(setSrc:)
|
|
72
72
|
func setSrc(srcDict: NSDictionary) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
let sourceDescription = try JSONDecoder().decode(SourceDescription.self, from: data)
|
|
77
|
-
self.src = sourceDescription
|
|
73
|
+
// build THEOplayer SourceDescription
|
|
74
|
+
if let src = THEOplayerRCTSourceDescriptionBuilder.buildSourceDescription(srcDict) {
|
|
75
|
+
self.src = src
|
|
78
76
|
if DEBUG_PROP_UPDATES { print("[NATIVE] src prop updated.") }
|
|
79
|
-
}
|
|
80
|
-
print(
|
|
77
|
+
} else {
|
|
78
|
+
if DEBUG_PROP_UPDATES { print("[NATIVE] failed to update THEOplayer source.") }
|
|
79
|
+
return
|
|
81
80
|
}
|
|
82
81
|
|
|
83
82
|
if (self.player == nil) {
|
|
@@ -12,7 +12,7 @@ let REMOVE_CUE: Int = 1
|
|
|
12
12
|
class THEOplayerRCTViewEventHandler {
|
|
13
13
|
// MARK: Members
|
|
14
14
|
private weak var player: THEOplayer?
|
|
15
|
-
private var currentPresentationMode = PresentationMode.inline // TheoPlayer's initial presentationMode
|
|
15
|
+
private var currentPresentationMode = THEOplayerSDK.PresentationMode.inline // TheoPlayer's initial presentationMode
|
|
16
16
|
|
|
17
17
|
// MARK: Events
|
|
18
18
|
var onNativePlay: RCTDirectEventBlock?
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-theoplayer",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.1",
|
|
4
4
|
"description": "A THEOplayer video component for react-native.",
|
|
5
5
|
"main": "lib/commonjs/index",
|
|
6
6
|
"module": "lib/module/index",
|
|
@@ -17,12 +17,10 @@
|
|
|
17
17
|
"!lib/typescript/example",
|
|
18
18
|
"!android/build",
|
|
19
19
|
"!ios/build",
|
|
20
|
-
"!**/__tests__",
|
|
21
20
|
"!**/__fixtures__",
|
|
22
21
|
"!**/__mocks__"
|
|
23
22
|
],
|
|
24
23
|
"scripts": {
|
|
25
|
-
"test": "jest",
|
|
26
24
|
"typescript": "tsc --noEmit",
|
|
27
25
|
"lint": "eslint \"**/*.{ts,tsx}\"",
|
|
28
26
|
"prepare": "bob build",
|
|
@@ -51,7 +49,6 @@
|
|
|
51
49
|
"@commitlint/config-conventional": "^11.0.0",
|
|
52
50
|
"@react-native-community/eslint-config": "^2.0.0",
|
|
53
51
|
"@release-it/conventional-changelog": "^2.0.0",
|
|
54
|
-
"@types/jest": "^26.0.0",
|
|
55
52
|
"@types/react": "^17.0.1",
|
|
56
53
|
"@types/react-native": "0.64.2",
|
|
57
54
|
"commitlint": "^11.0.0",
|
|
@@ -60,7 +57,6 @@
|
|
|
60
57
|
"eslint-plugin-prettier": "^3.1.3",
|
|
61
58
|
"eslint-plugin-react-native": "^4.0.0",
|
|
62
59
|
"husky": "^6.0.0",
|
|
63
|
-
"jest": "^26.0.1",
|
|
64
60
|
"pod-install": "^0.1.0",
|
|
65
61
|
"prettier": "^2.0.5",
|
|
66
62
|
"react": "17.0.1",
|
|
@@ -73,13 +69,6 @@
|
|
|
73
69
|
"react": "*",
|
|
74
70
|
"react-native": "*"
|
|
75
71
|
},
|
|
76
|
-
"jest": {
|
|
77
|
-
"preset": "react-native",
|
|
78
|
-
"modulePathIgnorePatterns": [
|
|
79
|
-
"<rootDir>/example/node_modules",
|
|
80
|
-
"<rootDir>/lib/"
|
|
81
|
-
]
|
|
82
|
-
},
|
|
83
72
|
"commitlint": {
|
|
84
73
|
"extends": [
|
|
85
74
|
"@commitlint/config-conventional"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|