@24i/smartapps-bigscreen-rnv-build-engine 0.17.21-alpha.2696 → 0.17.21
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/README.md +1 -1
- package/dist/src/scripts/release/notifySlack/makePayload.js +7 -7
- package/dist/src/scripts/smokeTest/notifySlack.js +2 -2
- package/dist/src/sdks/sdk-androidtv/sdkAndroidtv.js +7 -2
- package/dist/templates/platforms/androidtv/project/app/build.gradle +17 -4
- package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/configuration/BridgeConfig.kt +1 -0
- package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/global/utils/PlayerFactoryConfigured.kt +11 -0
- package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/global/utils/PlayerFactoryExoPlayerNpaw.kt +255 -0
- package/dist/templates/platforms/androidtv/project/build.gradle +2 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -228,7 +228,7 @@ If any platform needs any **platform-specific files**, those can be found also i
|
|
|
228
228
|
## How to set up new project with SmartApps BIGscreen build engine
|
|
229
229
|
There are a few things that are not included in the package and need to be added manually.
|
|
230
230
|
For example `renative.json` config file and `appConfigs` folder (both related to ReNative)
|
|
231
|
-
and `.
|
|
231
|
+
and `.github/workflows/*.yml` files (related to GitHub Actions CI).
|
|
232
232
|
|
|
233
233
|
> To **start a new project** with usage of our build process,
|
|
234
234
|
> please use [SmartApps BIGscreen Template repository](https://github.com/24i/smartapps-bigscreen-template),
|
|
@@ -37,15 +37,15 @@ const makePackagesPayload = (c) => {
|
|
|
37
37
|
.flat();
|
|
38
38
|
};
|
|
39
39
|
const makeHeaderPayload = (c, title, buttons) => {
|
|
40
|
-
const {
|
|
40
|
+
const { gitHubActionsBuild, gitHubRelease } = buttons || {};
|
|
41
41
|
const { owner, repo } = c.buildConfig.common.git || {};
|
|
42
42
|
const version = getVersion(c);
|
|
43
43
|
const envName = (0, resolvers_1.resolveBuildEnvName)(c.runtime.scheme);
|
|
44
44
|
const buttonsData = [];
|
|
45
|
-
if (
|
|
45
|
+
if (gitHubActionsBuild) {
|
|
46
46
|
buttonsData.push({
|
|
47
|
-
text: 'View
|
|
48
|
-
url: process.env.
|
|
47
|
+
text: 'View GitHub Actions Build Log',
|
|
48
|
+
url: process.env.CI_BUILD_WEB_URL || `https://github.com/${owner}/${repo}/actions/`,
|
|
49
49
|
});
|
|
50
50
|
}
|
|
51
51
|
if (gitHubRelease) {
|
|
@@ -70,20 +70,20 @@ const makePayload = (c, title, buttons) => ({
|
|
|
70
70
|
});
|
|
71
71
|
const makeDevelopmentPayload = (c) => {
|
|
72
72
|
const title = `There are new *development* builds for *${getCommonAppName(c)}* app!`;
|
|
73
|
-
const buttons = {
|
|
73
|
+
const buttons = { gitHubActionsBuild: true };
|
|
74
74
|
return makePayload(c, title, buttons);
|
|
75
75
|
};
|
|
76
76
|
exports.makeDevelopmentPayload = makeDevelopmentPayload;
|
|
77
77
|
const makeReleaseCandidatePayload = (c) => {
|
|
78
78
|
const title = `There are new *release candidate* builds for *${getCommonAppName(c)}* app!`;
|
|
79
|
-
const buttons = {
|
|
79
|
+
const buttons = { gitHubActionsBuild: true };
|
|
80
80
|
return makePayload(c, title, buttons);
|
|
81
81
|
};
|
|
82
82
|
exports.makeReleaseCandidatePayload = makeReleaseCandidatePayload;
|
|
83
83
|
const makeDistributionPayload = (c) => {
|
|
84
84
|
const title = `There are new *distribution* builds for *${getCommonAppName(c)}* app!`;
|
|
85
85
|
const isGitHubRelease = c.runtime.scheme === buildSchemes_1.BuildSchemes.RELEASE_PROD_DIST;
|
|
86
|
-
const buttons = {
|
|
86
|
+
const buttons = { gitHubActionsBuild: true, gitHubRelease: isGitHubRelease };
|
|
87
87
|
return makePayload(c, title, buttons);
|
|
88
88
|
};
|
|
89
89
|
exports.makeDistributionPayload = makeDistributionPayload;
|
|
@@ -27,8 +27,8 @@ const getSlackPayload = (params) => {
|
|
|
27
27
|
]),
|
|
28
28
|
slackBlockKitBuilder_1.Actions.buttons([
|
|
29
29
|
{
|
|
30
|
-
url: process.env.
|
|
31
|
-
text: 'View
|
|
30
|
+
url: process.env.CI_BUILD_WEB_URL || 'https://github.com/',
|
|
31
|
+
text: 'View GitHub Actions Build Log',
|
|
32
32
|
},
|
|
33
33
|
...(logsZipUrl ? [{
|
|
34
34
|
text: 'View Suitest Log files',
|
|
@@ -145,8 +145,8 @@ const configureProject = (c) => {
|
|
|
145
145
|
}
|
|
146
146
|
const appId = rnv_1.Common.getConfigProp(c, c.platform, 'id', '');
|
|
147
147
|
const minSdkVersion = rnv_1.Common.getConfigProp(c, c.platform, 'minSdkVersion', 21);
|
|
148
|
-
const targetSdkVersion = rnv_1.Common.getConfigProp(c, c.platform, 'targetSdkVersion',
|
|
149
|
-
const compileSdkVersion = rnv_1.Common.getConfigProp(c, c.platform, 'compileSdkVersion',
|
|
148
|
+
const targetSdkVersion = rnv_1.Common.getConfigProp(c, c.platform, 'targetSdkVersion', 34);
|
|
149
|
+
const compileSdkVersion = rnv_1.Common.getConfigProp(c, c.platform, 'compileSdkVersion', 34);
|
|
150
150
|
let versionCode = rnv_1.Common.getConfigProp(c, c.platform, 'versionCode');
|
|
151
151
|
if (typeof versionCode === 'undefined') {
|
|
152
152
|
const major = `${semVerObj.major}`.padStart(2, '0');
|
|
@@ -202,12 +202,17 @@ const configureEntryUrl = (c) => {
|
|
|
202
202
|
const entryUrl = getHostedAppEntryUrl(c);
|
|
203
203
|
const theoLicense = process.env['THEO_LICENSE'] ||
|
|
204
204
|
rnv_1.Common.getConfigProp(c, c.platform, 'theoLicense', '');
|
|
205
|
+
const npawAccountCode = process.env['NPAW_ACCOUNT_CODE'] ||
|
|
206
|
+
rnv_1.Common.getConfigProp(c, c.platform, 'npawAccountCode', '');
|
|
205
207
|
const injects = [{
|
|
206
208
|
pattern: '{{APP_URL}}',
|
|
207
209
|
override: entryUrl,
|
|
208
210
|
}, {
|
|
209
211
|
pattern: '{{THEO_LICENSE}}',
|
|
210
212
|
override: theoLicense,
|
|
213
|
+
}, {
|
|
214
|
+
pattern: '{{NPAW_ACCOUNT_CODE}}',
|
|
215
|
+
override: npawAccountCode,
|
|
211
216
|
}];
|
|
212
217
|
rnv_1.Common.addSystemInjects(c, injects);
|
|
213
218
|
rnv_1.FileUtils.writeCleanFile(buildGradleFilePath, buildGradleFilePath, injects, null, c);
|
|
@@ -4,6 +4,8 @@ apply plugin: 'kotlin-kapt'
|
|
|
4
4
|
|
|
5
5
|
def theoLicense = '{{THEO_LICENSE}}'
|
|
6
6
|
def useTheoPlayer = theoLicense != ''
|
|
7
|
+
def npawAccountCode = '{{NPAW_ACCOUNT_CODE}}'
|
|
8
|
+
def useNpawPlugin = npawAccountCode != ''
|
|
7
9
|
|
|
8
10
|
android {
|
|
9
11
|
namespace = 'com.twentyfouri.tvbridge'
|
|
@@ -37,6 +39,7 @@ android {
|
|
|
37
39
|
|
|
38
40
|
buildConfigField "String", "APP_URL", '"{{APP_URL}}"'
|
|
39
41
|
buildConfigField "String", "THEO_LICENSE", "\"$theoLicense\""
|
|
42
|
+
buildConfigField "String", "NPAW_ACCOUNT_CODE", "\"$npawAccountCode\""
|
|
40
43
|
buildConfigField "Boolean", "startWithHighVideoQuality", "true"
|
|
41
44
|
}
|
|
42
45
|
|
|
@@ -86,7 +89,7 @@ dependencies {
|
|
|
86
89
|
api "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4"
|
|
87
90
|
|
|
88
91
|
compileOnly "javax.annotation:jsr250-api:1.0"
|
|
89
|
-
implementation 'androidx.core:core-ktx:1.
|
|
92
|
+
implementation 'androidx.core:core-ktx:1.12.0'
|
|
90
93
|
implementation "androidx.appcompat:appcompat:1.6.1"
|
|
91
94
|
implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
|
|
92
95
|
|
|
@@ -94,17 +97,27 @@ dependencies {
|
|
|
94
97
|
kapt "com.google.dagger:dagger-compiler:2.48.1"
|
|
95
98
|
|
|
96
99
|
implementation "com.squareup.retrofit2:retrofit:2.9.0"
|
|
97
|
-
implementation "com.squareup.retrofit2:converter-gson:2.
|
|
100
|
+
implementation "com.squareup.retrofit2:converter-gson:2.9.0"
|
|
98
101
|
implementation "com.squareup.okhttp3:logging-interceptor:4.9.2"
|
|
99
102
|
implementation "com.squareup.okhttp3:okhttp:4.9.2"
|
|
100
103
|
if (useTheoPlayer) {
|
|
101
104
|
compileOnly "com.twentyfouri.player:exoplayer:0.7.0-alpha.3"
|
|
102
105
|
implementation "com.twentyfouri.player:theoplayer:0.7.0-alpha.3"
|
|
103
|
-
implementation "com.theoplayer.theoplayer-sdk-android:core:6.
|
|
106
|
+
implementation "com.theoplayer.theoplayer-sdk-android:core:6.2.1"
|
|
104
107
|
} else {
|
|
105
108
|
implementation "com.twentyfouri.player:exoplayer:0.7.0-alpha.3"
|
|
106
109
|
compileOnly "com.twentyfouri.player:theoplayer:0.7.0-alpha.3"
|
|
107
|
-
compileOnly "com.theoplayer.theoplayer-sdk-android:core:6.
|
|
110
|
+
compileOnly "com.theoplayer.theoplayer-sdk-android:core:6.2.1"
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (useNpawPlugin) {
|
|
114
|
+
implementation 'com.npaw.plugin:plugin:7.2.31'
|
|
115
|
+
implementation 'com.npaw.plugin:plugin-exoplayer:2.19.1-7.2.31'
|
|
116
|
+
implementation 'com.google.android.exoplayer:extension-okhttp:2.19.1'
|
|
117
|
+
} else {
|
|
118
|
+
compileOnly 'com.npaw.plugin:plugin:7.2.31'
|
|
119
|
+
compileOnly 'com.npaw.plugin:plugin-exoplayer:2.19.1-7.2.31'
|
|
120
|
+
compileOnly 'com.google.android.exoplayer:extension-okhttp:2.19.1'
|
|
108
121
|
}
|
|
109
122
|
|
|
110
123
|
implementation project(':common')
|
|
@@ -11,6 +11,9 @@ object PlayerFactoryConfigured {
|
|
|
11
11
|
if (bridgeConfig.theoLicense.isNotEmpty()) {
|
|
12
12
|
factory = factory ?: buildTheoFactory(bridgeConfig)
|
|
13
13
|
}
|
|
14
|
+
if (bridgeConfig.npawAccount.isNotEmpty()) {
|
|
15
|
+
factory = factory ?: buildNpawFactory(bridgeConfig)
|
|
16
|
+
}
|
|
14
17
|
factory = factory ?: buildExoFactory(bridgeConfig)
|
|
15
18
|
return factory ?: throw Exception("Cannot create player factory")
|
|
16
19
|
}
|
|
@@ -23,6 +26,14 @@ object PlayerFactoryConfigured {
|
|
|
23
26
|
}
|
|
24
27
|
}
|
|
25
28
|
|
|
29
|
+
private fun buildNpawFactory(bridgeConfig: BridgeConfig): PlayerFactoryBase? {
|
|
30
|
+
try {
|
|
31
|
+
return PlayerFactoryExoPlayerNpaw(bridgeConfig)
|
|
32
|
+
} catch (e: NoClassDefFoundError) {
|
|
33
|
+
return null
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
26
37
|
private fun buildTheoFactory(bridgeConfig: BridgeConfig): PlayerFactoryBase? {
|
|
27
38
|
try {
|
|
28
39
|
return PlayerFactoryTheoPlayerCustomized(bridgeConfig)
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
package com.twentyfouri.tvbridge.global.utils
|
|
2
|
+
|
|
3
|
+
import android.app.Application
|
|
4
|
+
import android.content.Context
|
|
5
|
+
import android.view.View
|
|
6
|
+
import android.view.ViewGroup
|
|
7
|
+
import com.google.android.exoplayer2.C
|
|
8
|
+
import com.google.android.exoplayer2.ExoPlayerLibraryInfo
|
|
9
|
+
import com.google.android.exoplayer2.drm.DefaultDrmSessionManager
|
|
10
|
+
import com.google.android.exoplayer2.drm.DrmSessionManager
|
|
11
|
+
import com.google.android.exoplayer2.drm.FrameworkMediaDrm
|
|
12
|
+
import com.google.android.exoplayer2.drm.MediaDrmCallback
|
|
13
|
+
import com.google.android.exoplayer2.ext.okhttp.OkHttpDataSource
|
|
14
|
+
import com.google.android.exoplayer2.upstream.HttpDataSource
|
|
15
|
+
import com.google.android.exoplayer2.upstream.cache.CacheDataSource
|
|
16
|
+
import com.npaw.NpawPlugin
|
|
17
|
+
import com.npaw.analytics.video.VideoAdapter
|
|
18
|
+
import com.npaw.analytics.video.VideoOptions
|
|
19
|
+
import com.npaw.core.options.AnalyticsOptions
|
|
20
|
+
import com.npaw.exoplayer.ExoPlayerAdapter
|
|
21
|
+
import com.npaw.exoplayer.ExoPlayerBalancer
|
|
22
|
+
import com.twentyfouri.player.base.DrmPlayready
|
|
23
|
+
import com.twentyfouri.player.base.DrmWidevine
|
|
24
|
+
import com.twentyfouri.player.base.PlayerBase
|
|
25
|
+
import com.twentyfouri.player.base.Source
|
|
26
|
+
import com.twentyfouri.player.base.SourceAuthorization
|
|
27
|
+
import com.twentyfouri.player.base.SourceDrm
|
|
28
|
+
import com.twentyfouri.player.base.SourceMetadata
|
|
29
|
+
import com.twentyfouri.player.base.buildUpon
|
|
30
|
+
import com.twentyfouri.player.base.getBoolean
|
|
31
|
+
import com.twentyfouri.player.base.getString
|
|
32
|
+
import com.twentyfouri.player.exoplayer.AuthorizedDataSourceProvider
|
|
33
|
+
import com.twentyfouri.player.exoplayer.DefaultDrmSessionManagerProvider
|
|
34
|
+
import com.twentyfouri.player.exoplayer.DefaultPlayerComponents
|
|
35
|
+
import com.twentyfouri.player.exoplayer.DefaultSharedComponents
|
|
36
|
+
import com.twentyfouri.player.exoplayer.DrmSessionManagerProvider
|
|
37
|
+
import com.twentyfouri.player.exoplayer.PlayerComponents
|
|
38
|
+
import com.twentyfouri.player.exoplayer.PlayerExoPlayer
|
|
39
|
+
import com.twentyfouri.player.exoplayer.PlayerFactoryExoPlayer
|
|
40
|
+
import com.twentyfouri.player.exoplayer.PlayerViewExoPlayer
|
|
41
|
+
import com.twentyfouri.player.exoplayer.SharedComponents
|
|
42
|
+
import com.twentyfouri.tvbridge.BuildConfig
|
|
43
|
+
import com.twentyfouri.tvbridge.configuration.BridgeConfig
|
|
44
|
+
import com.npaw.core.util.extensions.Log as NpawLog
|
|
45
|
+
|
|
46
|
+
class PlayerFactoryExoPlayerNpaw(
|
|
47
|
+
private val config: BridgeConfig
|
|
48
|
+
) : PlayerFactoryExoPlayer(), PlayerFactoryVersion {
|
|
49
|
+
|
|
50
|
+
override val engineName: String = "Exoplayer"
|
|
51
|
+
|
|
52
|
+
override val engineVersion: String = ExoPlayerLibraryInfo.VERSION
|
|
53
|
+
|
|
54
|
+
override fun createSharedComponents(context: Context): SharedComponents =
|
|
55
|
+
CustomizedSharedComponents(context)
|
|
56
|
+
|
|
57
|
+
override fun createView(parent: ViewGroup): View {
|
|
58
|
+
return PlayerViewExoPlayer(parent.context).also {
|
|
59
|
+
val basePlayer = createPlayer(parent.context)
|
|
60
|
+
val npawPlugin = (
|
|
61
|
+
(basePlayer.components as CustomizedPlayerComponents)
|
|
62
|
+
.sharedComponents as CustomizedSharedComponents
|
|
63
|
+
).npawPlugin
|
|
64
|
+
val npawPlayer = NpawPlayer(basePlayer, npawPlugin)
|
|
65
|
+
trackPlayer(npawPlayer)
|
|
66
|
+
it.player = npawPlayer
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
private inner class CustomizedSharedComponents(context: Context) : DefaultSharedComponents(context) {
|
|
71
|
+
|
|
72
|
+
val application = context.applicationContext as? Application
|
|
73
|
+
?: throw IllegalStateException("Missing application")
|
|
74
|
+
|
|
75
|
+
val npawPlugin: NpawPlugin = NpawPlugin
|
|
76
|
+
.Builder(application, config.npawAccount)
|
|
77
|
+
.setLogLevel(if (BuildConfig.DEBUG) NpawLog.Level.VERBOSE else NpawLog.Level.ERROR)
|
|
78
|
+
.build()
|
|
79
|
+
|
|
80
|
+
val npawBalancer = ExoPlayerBalancer(npawPlugin)
|
|
81
|
+
|
|
82
|
+
override fun destroy() {
|
|
83
|
+
super.destroy()
|
|
84
|
+
npawPlugin.destroy()
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
override val drmProvider: DrmSessionManagerProvider by lazy { CustomizedDrmSessionManagerProvider() }
|
|
88
|
+
|
|
89
|
+
override val applicationName: String
|
|
90
|
+
get() = config.playerAppName ?: super.applicationName
|
|
91
|
+
|
|
92
|
+
override fun buildIsolatedComponents(): PlayerComponents {
|
|
93
|
+
return CustomizedPlayerComponents(this)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
override val baseHttpFactory: HttpDataSource.Factory by lazy {
|
|
97
|
+
npawBalancer.dataSourceFactory as OkHttpDataSource.Factory
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
override val dataSourceFactory: AuthorizedDataSourceProvider by lazy {
|
|
101
|
+
object : AuthorizedDataSourceProvider {
|
|
102
|
+
override fun buildDataSourceFactory(authorization: SourceAuthorization?): CacheDataSource.Factory {
|
|
103
|
+
return buildReadOnlyDataSourceFactory(baseHttpFactory)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
override fun buildHttpDataSourceFactory(authorization: SourceAuthorization?): HttpDataSource.Factory {
|
|
107
|
+
return baseHttpFactory
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
override val cacheDataSourceFactory: AuthorizedDataSourceProvider by lazy {
|
|
113
|
+
dataSourceFactory
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
private inner class CustomizedPlayerComponents(shared: SharedComponents) : DefaultPlayerComponents(shared) {
|
|
118
|
+
override val handleAudioFocus: Boolean
|
|
119
|
+
get() = false
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
private class CustomizedDrmSessionManagerProvider : DefaultDrmSessionManagerProvider() {
|
|
123
|
+
override fun buildDrmSessionManager(
|
|
124
|
+
dataSourceFactory: AuthorizedDataSourceProvider,
|
|
125
|
+
source: Source,
|
|
126
|
+
sourceDrm: SourceDrm
|
|
127
|
+
): DrmSessionManager? {
|
|
128
|
+
if (sourceDrm is SourceDrmOverridden) {
|
|
129
|
+
return buildDrmOverridden(dataSourceFactory, sourceDrm)
|
|
130
|
+
} else {
|
|
131
|
+
return super.buildDrmSessionManager(dataSourceFactory, source, sourceDrm)
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
private fun buildDrmOverridden(dataSourceFactory: AuthorizedDataSourceProvider, sourceDrm: SourceDrmOverridden): DrmSessionManager? {
|
|
136
|
+
val drmUuid = when (sourceDrm.packageName) {
|
|
137
|
+
DrmWidevine.packageName -> C.WIDEVINE_UUID
|
|
138
|
+
DrmPlayready.packageName -> C.PLAYREADY_UUID
|
|
139
|
+
else -> C.UUID_NIL
|
|
140
|
+
}
|
|
141
|
+
val licenseUrl = sourceDrm.licenseServer?.toString() ?: ""
|
|
142
|
+
val forceLicenseUrl = sourceDrm.forceLicenseServer
|
|
143
|
+
val httpDataSourceFactory = dataSourceFactory.buildHttpDataSourceFactory(sourceDrm.authorization)
|
|
144
|
+
|
|
145
|
+
val drmCallback = LoggingDrmCallback(
|
|
146
|
+
OverriddenHttpMediaDrmCallback(
|
|
147
|
+
licenseUrl,
|
|
148
|
+
forceLicenseUrl,
|
|
149
|
+
httpDataSourceFactory
|
|
150
|
+
),
|
|
151
|
+
licenseUrl
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
return DefaultDrmSessionManager.Builder()
|
|
155
|
+
.setUuidAndExoMediaDrmProvider(drmUuid, FrameworkMediaDrm.DEFAULT_PROVIDER)
|
|
156
|
+
.setMultiSession(false)
|
|
157
|
+
.build(drmCallback)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
override fun buildDrmCallback(licenseUrl: String, forceLicenseUrl: Boolean, httpDataSourceFactory: HttpDataSource.Factory): MediaDrmCallback {
|
|
161
|
+
return LoggingDrmCallback(super.buildDrmCallback(licenseUrl, forceLicenseUrl, httpDataSourceFactory), licenseUrl)
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
private class NpawPlayer(
|
|
166
|
+
val basePlayer: PlayerExoPlayer,
|
|
167
|
+
val npawPlugin: NpawPlugin
|
|
168
|
+
) : PlayerBase by basePlayer {
|
|
169
|
+
|
|
170
|
+
var exoPlayerAdapter: ExoPlayerAdapter? = null
|
|
171
|
+
|
|
172
|
+
var videoAdapter: VideoAdapter? = null
|
|
173
|
+
set(value) {
|
|
174
|
+
field?.destroy()
|
|
175
|
+
field = value
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
fun extractYouboraAnalyticsOptions(source: Source?, target: AnalyticsOptions) {
|
|
179
|
+
if (source == null) return
|
|
180
|
+
val jsonAnalyticsArray = source.extras?.optJSONArray("analytics") ?: return
|
|
181
|
+
for (index in 0 until jsonAnalyticsArray.length()) {
|
|
182
|
+
val jsonAnalytics = jsonAnalyticsArray.getJSONObject(index)
|
|
183
|
+
if (jsonAnalytics.getString("integration", "") != "youbora") continue
|
|
184
|
+
jsonAnalytics.keys().forEach { key ->
|
|
185
|
+
when (key) {
|
|
186
|
+
"app.name" -> target.appName = jsonAnalytics.getString(key, null)
|
|
187
|
+
"app.releaseVersion" -> target.appReleaseVersion = jsonAnalytics.getString(key, null)
|
|
188
|
+
"device.id" -> target.deviceId = jsonAnalytics.getString(key, null)
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
fun extractYouboraVideoOptions(source: Source?, target: VideoOptions) {
|
|
195
|
+
if (source == null) return
|
|
196
|
+
val jsonAnalyticsArray = source.extras?.optJSONArray("analytics") ?: return
|
|
197
|
+
for (index in 0 until jsonAnalyticsArray.length()) {
|
|
198
|
+
val jsonAnalytics = jsonAnalyticsArray.getJSONObject(index)
|
|
199
|
+
if (jsonAnalytics.getString("integration", "") != "youbora") continue
|
|
200
|
+
jsonAnalytics.keys().forEach { key ->
|
|
201
|
+
when (key) {
|
|
202
|
+
"content.id" -> target.contentId = jsonAnalytics.getString(key, null)
|
|
203
|
+
"content.title" -> target.contentTitle = jsonAnalytics.getString(key, null)
|
|
204
|
+
"content.isLive" -> target.live = jsonAnalytics.getBoolean(key, false)
|
|
205
|
+
"content.type" -> target.contentType = jsonAnalytics.getString(key, null)
|
|
206
|
+
"content.program" -> target.program = jsonAnalytics.getString(key, null)
|
|
207
|
+
"content.channel" -> target.contentChannel = jsonAnalytics.getString(key, null)
|
|
208
|
+
"content.episodeTitle" -> target.contentEpisodeTitle = jsonAnalytics.getString(key, null)
|
|
209
|
+
"content.season" -> target.contentSeason = jsonAnalytics.getString(key, null)
|
|
210
|
+
"content.tvShow" -> target.contentTvShow = jsonAnalytics.getString(key, null)
|
|
211
|
+
"content.customDimension.1" -> target.contentCustomDimension1 = jsonAnalytics.getString(key, null)
|
|
212
|
+
"content.customDimension.2" -> target.contentCustomDimension2 = jsonAnalytics.getString(key, null)
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
override var source: Source?
|
|
219
|
+
get() = basePlayer.source
|
|
220
|
+
set(value) {
|
|
221
|
+
exoPlayerAdapter = null
|
|
222
|
+
videoAdapter = null
|
|
223
|
+
if (value != null) {
|
|
224
|
+
val videoOptions = VideoOptions()
|
|
225
|
+
extractYouboraAnalyticsOptions(value, npawPlugin.analyticsOptions)
|
|
226
|
+
extractYouboraVideoOptions(value, videoOptions)
|
|
227
|
+
|
|
228
|
+
var adjustedSource = value
|
|
229
|
+
if (value.metadata?.title.isNullOrEmpty() && !videoOptions.contentTitle.isNullOrEmpty()) {
|
|
230
|
+
adjustedSource = value.buildUpon {
|
|
231
|
+
metadata = (metadata?.buildUpon() ?: SourceMetadata.Builder()).apply {
|
|
232
|
+
title = videoOptions.contentTitle
|
|
233
|
+
}.build()
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
basePlayer.source = adjustedSource
|
|
238
|
+
exoPlayerAdapter = ExoPlayerAdapter(basePlayer.components.context, basePlayer.exoPlayer)
|
|
239
|
+
videoAdapter = npawPlugin.videoBuilder()
|
|
240
|
+
.setPlayerAdapter(exoPlayerAdapter)
|
|
241
|
+
.setOptions(videoOptions)
|
|
242
|
+
.build()
|
|
243
|
+
} else {
|
|
244
|
+
basePlayer.source = null
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
override fun destroy() {
|
|
249
|
+
exoPlayerAdapter = null
|
|
250
|
+
videoAdapter = null
|
|
251
|
+
basePlayer.destroy()
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
package/package.json
CHANGED