@24i/smartapps-bigscreen-rnv-build-engine 0.17.2 → 0.17.3-alpha.2

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.
Files changed (88) hide show
  1. package/dist/src/__tests__/resolvers/resolveBuildFileBaseName.spec.js +80 -0
  2. package/dist/src/resolvers/index.js +3 -1
  3. package/dist/src/resolvers/resolveBuildFileBaseName.js +34 -0
  4. package/dist/src/resolvers/resolveBuildFileName.js +3 -27
  5. package/dist/src/scripts/releaseAllWithScheme.js +1 -1
  6. package/dist/src/sdks/index.js +5 -1
  7. package/dist/src/sdks/sdk-androidtv/index.js +17 -0
  8. package/dist/src/sdks/sdk-androidtv/sdkAndroidtv.js +264 -0
  9. package/dist/src/sdks/sdk-utils/sdk-installer/services/unzip.js +3 -2
  10. package/dist/src/tasks/task.rnv.build.js +3 -1
  11. package/dist/src/tasks/task.rnv.configure.js +3 -1
  12. package/dist/src/tasks/task.rnv.platform.configure.js +4 -1
  13. package/dist/templates/platforms/_shared/template.js +3 -3
  14. package/dist/templates/platforms/androidtv/project/README.md +196 -0
  15. package/dist/templates/platforms/androidtv/project/amazoniap/build.gradle +37 -0
  16. package/dist/templates/platforms/androidtv/project/amazoniap/consumer-rules.pro +0 -0
  17. package/dist/templates/platforms/androidtv/project/amazoniap/libs/in-app-purchasing-2.0.76.jar +0 -0
  18. package/dist/templates/platforms/androidtv/project/amazoniap/proguard-rules.pro +21 -0
  19. package/dist/templates/platforms/androidtv/project/amazoniap/src/main/AndroidManifest.xml +4 -0
  20. package/dist/templates/platforms/androidtv/project/amazoniap/src/main/java/com/twentyfouri/bridgetv/amazoniap/AmazonIapSevice.kt +106 -0
  21. package/dist/templates/platforms/androidtv/project/app/build.gradle +112 -0
  22. package/dist/templates/platforms/androidtv/project/app/proguard-rules.pro +32 -0
  23. package/dist/templates/platforms/androidtv/project/app/src/bigscreenAppstage/java/com/twentyfouri/tvbridge/Flavor.kt +5 -0
  24. package/dist/templates/platforms/androidtv/project/app/src/bigscreenAppstage/res/raw/configuration.json +9 -0
  25. package/dist/templates/platforms/androidtv/project/app/src/main/AndroidManifest.xml +53 -0
  26. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/FlavorBase.kt +12 -0
  27. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/bridge/BridgeFromJavaScript.kt +392 -0
  28. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/bridge/BridgeToJavaScript.kt +89 -0
  29. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/configuration/BridgeConfig.kt +16 -0
  30. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/configuration/ConfigCallback.kt +6 -0
  31. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/configuration/ConfigProvider.kt +27 -0
  32. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/configuration/Drm.kt +10 -0
  33. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/configuration/UserAgent.kt +6 -0
  34. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/global/BaseApplication.kt +73 -0
  35. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/global/di/ActivityComponent.kt +13 -0
  36. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/global/di/ActivityModule.kt +17 -0
  37. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/global/di/ApplicationComponent.kt +26 -0
  38. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/global/di/ApplicationModule.kt +51 -0
  39. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/global/di/PerActivity.kt +26 -0
  40. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/global/utils/LocalStorage.kt +30 -0
  41. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/global/utils/LoggingDrmCallback.kt +38 -0
  42. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/global/utils/OverriddenHttpMediaDrmCallback.kt +134 -0
  43. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/global/utils/PlayerFactoryExoPlayerCustomized.kt +84 -0
  44. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/global/utils/SimpleActivityLifecycleCallback.kt +32 -0
  45. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/global/utils/SourceDrmOverridden.kt +49 -0
  46. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/jump/JumpAnalytics.kt +211 -0
  47. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/sound/TouchPlayer.kt +86 -0
  48. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/webview/client/BridgeWebView.kt +82 -0
  49. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/webview/client/BridgeWebViewClient.kt +114 -0
  50. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/webview/model/AnalyticsPlaybackInfo.kt +10 -0
  51. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/webview/model/ContentModel.kt +14 -0
  52. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/webview/model/DrmModel.kt +20 -0
  53. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/webview/model/MediaEventType.kt +20 -0
  54. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/webview/parser/ContentModelParser.kt +16 -0
  55. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/webview/parser/DeviceInfoParser.kt +22 -0
  56. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/webview/parser/PlaybackInfoParser.kt +10 -0
  57. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/webview/parser/TrackJsonModelParser.kt +58 -0
  58. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/webview/view/Mainview.kt +20 -0
  59. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/webview/view/PlayerCache.kt +15 -0
  60. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/webview/view/WebViewActivity.kt +306 -0
  61. package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/webview/viewmodel/WebViewModel.kt +609 -0
  62. package/dist/templates/platforms/androidtv/project/app/src/main/res/drawable/button_background_focus.xml +10 -0
  63. package/dist/templates/platforms/androidtv/project/app/src/main/res/drawable/button_background_normal.xml +7 -0
  64. package/dist/templates/platforms/androidtv/project/app/src/main/res/drawable/button_background_pressed.xml +7 -0
  65. package/dist/templates/platforms/androidtv/project/app/src/main/res/drawable/button_focus.xml +8 -0
  66. package/dist/templates/platforms/androidtv/project/app/src/main/res/layout/activity_web_view.xml +76 -0
  67. package/dist/templates/platforms/androidtv/project/app/src/main/res/raw/click.ogg +0 -0
  68. package/dist/templates/platforms/androidtv/project/app/src/main/res/values/styles.xml +12 -0
  69. package/dist/templates/platforms/androidtv/project/app/src/main/res/xml/network_security_config.xml +4 -0
  70. package/dist/templates/platforms/androidtv/project/build.gradle +48 -0
  71. package/dist/templates/platforms/androidtv/project/common/build.gradle +36 -0
  72. package/dist/templates/platforms/androidtv/project/common/consumer-rules.pro +0 -0
  73. package/dist/templates/platforms/androidtv/project/common/proguard-rules.pro +21 -0
  74. package/dist/templates/platforms/androidtv/project/common/src/main/AndroidManifest.xml +4 -0
  75. package/dist/templates/platforms/androidtv/project/common/src/main/java/com/twentyfouri/tvbridge/common/IapService.kt +114 -0
  76. package/dist/templates/platforms/androidtv/project/googleiap/build.gradle +38 -0
  77. package/dist/templates/platforms/androidtv/project/googleiap/consumer-rules.pro +0 -0
  78. package/dist/templates/platforms/androidtv/project/googleiap/proguard-rules.pro +21 -0
  79. package/dist/templates/platforms/androidtv/project/googleiap/src/main/AndroidManifest.xml +6 -0
  80. package/dist/templates/platforms/androidtv/project/googleiap/src/main/java/com/twentyfouri/tvbridge/googleiap/GoogleIapService.kt +29 -0
  81. package/dist/templates/platforms/androidtv/project/gradle/wrapper/gradle-wrapper.jar +0 -0
  82. package/dist/templates/platforms/androidtv/project/gradle/wrapper/gradle-wrapper.properties +6 -0
  83. package/dist/templates/platforms/androidtv/project/gradle.properties +4 -0
  84. package/dist/templates/platforms/androidtv/project/gradlew +185 -0
  85. package/dist/templates/platforms/androidtv/project/gradlew.bat +104 -0
  86. package/dist/templates/platforms/androidtv/project/proguard-rules.pro +42 -0
  87. package/dist/templates/platforms/androidtv/project/settings.gradle +4 -0
  88. package/package.json +3 -2
@@ -0,0 +1,51 @@
1
+ package com.twentyfouri.tvbridge.global.di
2
+
3
+ import android.content.Context
4
+ import com.twentyfouri.player.base.PlayerFactoryBase
5
+ import com.twentyfouri.tvbridge.Flavor
6
+ import com.twentyfouri.tvbridge.common.NullIapService
7
+ import com.twentyfouri.tvbridge.configuration.BridgeConfig
8
+ import com.twentyfouri.tvbridge.global.BaseApplication
9
+ import com.twentyfouri.tvbridge.global.utils.LocalStorage
10
+ import com.twentyfouri.tvbridge.global.utils.PlayerFactoryExoPlayerCustomized
11
+ import com.twentyfouri.tvbridge.sound.TouchPlayer
12
+ import dagger.Module
13
+ import dagger.Provides
14
+ import javax.inject.Singleton
15
+
16
+ @Module
17
+ class ApplicationModule(
18
+ private val baseApplication: BaseApplication,
19
+ private val configuration: BridgeConfig
20
+ ) {
21
+ @Provides
22
+ fun getApplication() = baseApplication
23
+
24
+ @Provides
25
+ fun getConfiguration() = configuration
26
+
27
+ @Provides
28
+ fun provideApplicationContext(): Context = baseApplication
29
+
30
+ @Singleton
31
+ @Provides
32
+ fun provideLocalStorage() = LocalStorage(baseApplication.applicationContext)
33
+
34
+ @Singleton
35
+ @Provides
36
+ fun provideTouchPlayer() = TouchPlayer(baseApplication)
37
+
38
+ @Singleton
39
+ @Provides
40
+ fun provideIapService() = Flavor()
41
+ .getIapServiceFactories()
42
+ .firstOrNull { it.detectSupport(baseApplication) }
43
+ ?.build(baseApplication)
44
+ ?: NullIapService()
45
+
46
+ @Provides
47
+ @Singleton
48
+ fun providePlayerFactory(config: BridgeConfig): PlayerFactoryBase =
49
+ PlayerFactoryExoPlayerCustomized(config)
50
+
51
+ }
@@ -0,0 +1,26 @@
1
+ package com.twentyfouri.tvbridge.global.di
2
+
3
+ import javax.inject.Scope
4
+
5
+ /*
6
+ * Copyright (C) 2013 Square, Inc.
7
+ *
8
+ * Licensed under the Apache License, Version 2.0 (the "License");
9
+ * you may not use this file except in compliance with the License.
10
+ * You may obtain a copy of the License at
11
+ *
12
+ * http://www.apache.org/licenses/LICENSE-2.0
13
+ *
14
+ * Unless required by applicable law or agreed to in writing, software
15
+ * distributed under the License is distributed on an "AS IS" BASIS,
16
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
+ * See the License for the specific language governing permissions and
18
+ * limitations under the License.
19
+ */ /**
20
+ * A scoping annotation to permit objects whose lifetime should
21
+ * conform to the life of the activity to be memoized in the
22
+ * correct component.
23
+ */
24
+ @Scope
25
+ @kotlin.annotation.Retention(AnnotationRetention.RUNTIME)
26
+ annotation class PerActivity
@@ -0,0 +1,30 @@
1
+ package com.twentyfouri.tvbridge.global.utils
2
+
3
+ import android.content.Context
4
+ import android.content.SharedPreferences
5
+
6
+ class LocalStorage(context: Context) {
7
+
8
+ private val preferences: SharedPreferences =
9
+ context.applicationContext.getSharedPreferences(SHARED_PREFERENCES, Context.MODE_PRIVATE)
10
+
11
+ fun saveCookieJson(key: String?, value: String?) {
12
+ val editor = preferences.edit()
13
+ editor.putString(key, value)
14
+ editor.apply()
15
+ }
16
+
17
+ fun removeFromLocalStorage(key: String?) {
18
+ val editor = preferences.edit()
19
+ editor.remove(key)
20
+ editor.apply()
21
+ }
22
+
23
+ fun getFromLocalStorage(key: String?): String? {
24
+ return preferences.getString(key, null)
25
+ }
26
+
27
+ companion object {
28
+ private const val SHARED_PREFERENCES = "com.twentyfouri.tvbridge"
29
+ }
30
+ }
@@ -0,0 +1,38 @@
1
+ package com.twentyfouri.tvbridge.global.utils
2
+
3
+ import android.util.Base64
4
+ import android.util.Log
5
+ import com.google.android.exoplayer2.drm.ExoMediaDrm
6
+ import com.google.android.exoplayer2.drm.MediaDrmCallback
7
+ import java.util.*
8
+
9
+ class LoggingDrmCallback(
10
+ private val base: MediaDrmCallback,
11
+ private val licenseUrl: String? = null
12
+ ) : MediaDrmCallback {
13
+ override fun executeProvisionRequest(
14
+ uuid: UUID,
15
+ request: ExoMediaDrm.ProvisionRequest
16
+ ): ByteArray {
17
+ return base.executeProvisionRequest(uuid, request)
18
+ }
19
+
20
+ override fun executeKeyRequest(uuid: UUID, request: ExoMediaDrm.KeyRequest): ByteArray {
21
+ if (com.twentyfouri.player.exoplayer.BuildConfig.DEBUG) {
22
+ Log.v(TAG, "DRM Embedded URL: ${request.licenseServerUrl}")
23
+ Log.v(TAG, "DRM Default URL: $licenseUrl")
24
+ Log.v(TAG, "DRM request:\n${request.data.toBase64()}")
25
+ }
26
+ val response = base.executeKeyRequest(uuid, request)
27
+ if (com.twentyfouri.player.exoplayer.BuildConfig.DEBUG) {
28
+ Log.v(TAG, "DRM response:\n" + response.toBase64())
29
+ }
30
+ return response
31
+ }
32
+
33
+ private fun ByteArray.toBase64(): String = Base64.encodeToString(this, Base64.DEFAULT)
34
+
35
+ companion object {
36
+ const val TAG = "DrmCallback"
37
+ }
38
+ }
@@ -0,0 +1,134 @@
1
+ package com.twentyfouri.tvbridge.global.utils
2
+
3
+ import android.net.Uri
4
+ import android.util.Base64
5
+ import android.util.Log
6
+ import com.google.android.exoplayer2.C
7
+ import com.google.android.exoplayer2.drm.ExoMediaDrm
8
+ import com.google.android.exoplayer2.drm.MediaDrmCallback
9
+ import com.google.android.exoplayer2.upstream.DataSourceInputStream
10
+ import com.google.android.exoplayer2.upstream.DataSpec
11
+ import com.google.android.exoplayer2.upstream.HttpDataSource
12
+ import com.google.android.exoplayer2.util.Util
13
+ import com.twentyfouri.tvbridge.BuildConfig
14
+ import org.json.JSONException
15
+ import org.json.JSONObject
16
+ import java.io.BufferedReader
17
+ import java.io.IOException
18
+ import java.io.InputStreamReader
19
+ import java.net.MalformedURLException
20
+ import java.net.URL
21
+ import java.net.URLEncoder
22
+ import java.util.HashMap
23
+ import java.util.UUID
24
+
25
+ class OverriddenHttpMediaDrmCallback(
26
+ private val defaultLicenseUrl: String?,
27
+ private val forceDefaultLicenseUrl: Boolean,
28
+ private val dataSourceFactory: HttpDataSource.Factory
29
+ ) : MediaDrmCallback {
30
+
31
+ @Throws(IOException::class)
32
+ override fun executeProvisionRequest(uuid: UUID, request: ExoMediaDrm.ProvisionRequest): ByteArray {
33
+ Log.d(TAG, "executeProvisionRequest")
34
+ val url = request.defaultUrl + "&signedRequest=" + String(request.data)
35
+ return executePost(dataSourceFactory, url, ByteArray(0), null)
36
+ }
37
+
38
+ @Throws(Exception::class)
39
+ override fun executeKeyRequest(uuid: UUID, request: ExoMediaDrm.KeyRequest): ByteArray {
40
+ Log.d(TAG, "executeKeyRequest")
41
+ var url: String? = request.licenseServerUrl
42
+ if (forceDefaultLicenseUrl || url.isNullOrEmpty()) {
43
+ url = defaultLicenseUrl
44
+ }
45
+ val requestProperties: MutableMap<String, String> = HashMap()
46
+ // Add standard request properties for supported schemes.
47
+ val contentType = "text/plain"
48
+ requestProperties["Content-Type"] = contentType
49
+ if (C.PLAYREADY_UUID == uuid) {
50
+ requestProperties["SOAPAction"] = "http://schemas.microsoft.com/DRM/2007/03/protocols/AcquireLicense"
51
+ }
52
+
53
+ //adding data to url
54
+ val challenge = request.data
55
+ val encoded = URLEncoder.encode(Base64.encodeToString(challenge, Base64.NO_WRAP), "UTF-8")
56
+ url = appendQuery(url, "_widevineChallenge=$encoded")
57
+ if (BuildConfig.DEBUG) {
58
+ Log.d(TAG, "Executing post on url $url with content type $contentType")
59
+ }
60
+ return executeGet(url)
61
+ }
62
+
63
+ companion object {
64
+ private const val TAG = "DrmCallback"
65
+
66
+ private fun executeGet(urlString: String): ByteArray {
67
+ try {
68
+ val licenserRequest = URL(urlString)
69
+ val yc = licenserRequest.openConnection()
70
+ val input = BufferedReader(InputStreamReader(yc.getInputStream()))
71
+ val builder = StringBuilder()
72
+ var inputLine: String?
73
+ while (input.readLine().also { inputLine = it } != null) {
74
+ builder.append(inputLine)
75
+ }
76
+ input.close()
77
+ val jsonObject = JSONObject(builder.toString())
78
+ val container = jsonObject.getJSONObject("getWidevineLicenseResponse")
79
+ val license = container.getString("license")
80
+ if (BuildConfig.DEBUG) {
81
+ Log.d(TAG, "Finished post: $license")
82
+ }
83
+ return Base64.decode(license, Base64.NO_WRAP)
84
+ } catch (e: MalformedURLException) {
85
+ e.printStackTrace()
86
+ } catch (e: IOException) {
87
+ e.printStackTrace()
88
+ } catch (e: JSONException) {
89
+ e.printStackTrace()
90
+ }
91
+ return byteArrayOf()
92
+ }
93
+
94
+ @Throws(IOException::class)
95
+ private fun executePost(
96
+ dataSourceFactory: HttpDataSource.Factory,
97
+ url: String,
98
+ data: ByteArray,
99
+ requestProperties: Map<String, String>?
100
+ ): ByteArray {
101
+ Log.d(TAG, "executePost")
102
+ val dataSource = dataSourceFactory.createDataSource()
103
+ if (requestProperties != null) {
104
+ for ((key, value) in requestProperties) {
105
+ dataSource.setRequestProperty(key, value)
106
+ }
107
+ }
108
+ val dataSpec = DataSpec.Builder()
109
+ .setUri(Uri.parse(url))
110
+ .setFlags(DataSpec.FLAG_ALLOW_GZIP)
111
+ .setHttpMethod(DataSpec.HTTP_METHOD_POST)
112
+ .setHttpBody(data)
113
+ .setHttpRequestHeaders(requestProperties ?: emptyMap())
114
+ .build()
115
+ val inputStream = DataSourceInputStream(dataSource, dataSpec)
116
+ return try {
117
+ Util.toByteArray(inputStream)
118
+ } finally {
119
+ Util.closeQuietly(inputStream)
120
+ }
121
+ }
122
+
123
+ fun appendQuery(url: String?, appendQuery: String): String {
124
+ val oldUri = Uri.parse(url)
125
+ var newQuery = oldUri.query
126
+ if (newQuery == null) {
127
+ newQuery = appendQuery
128
+ } else {
129
+ newQuery += "&$appendQuery"
130
+ }
131
+ return oldUri.scheme + "://" + oldUri.authority + oldUri.path + "?" + newQuery
132
+ }
133
+ }
134
+ }
@@ -0,0 +1,84 @@
1
+ package com.twentyfouri.tvbridge.global.utils
2
+
3
+ import android.content.Context
4
+ import com.google.android.exoplayer2.C
5
+ import com.google.android.exoplayer2.drm.DefaultDrmSessionManager
6
+ import com.google.android.exoplayer2.drm.DrmSessionManager
7
+ import com.google.android.exoplayer2.drm.FrameworkMediaDrm
8
+ import com.google.android.exoplayer2.drm.MediaDrmCallback
9
+ import com.google.android.exoplayer2.upstream.HttpDataSource
10
+ import com.google.android.exoplayer2.util.Util
11
+ import com.twentyfouri.player.base.DrmPlayready
12
+ import com.twentyfouri.player.base.DrmWidevine
13
+ import com.twentyfouri.player.base.Source
14
+ import com.twentyfouri.player.base.SourceDrm
15
+ import com.twentyfouri.player.exoplayer.*
16
+ import com.twentyfouri.tvbridge.configuration.BridgeConfig
17
+
18
+ class PlayerFactoryExoPlayerCustomized(
19
+ private val config: BridgeConfig
20
+ ) : PlayerFactoryExoPlayer() {
21
+ override fun createSharedComponents(context: Context): SharedComponents =
22
+ CustomizedSharedComponents(context)
23
+
24
+ private inner class CustomizedSharedComponents(context: Context) : DefaultSharedComponents(context) {
25
+
26
+ override val drmProvider: DrmSessionManagerProvider by lazy { CustomizedDrmSessionManagerProvider() }
27
+
28
+ override val applicationName: String
29
+ get() = config.playerAppName ?: super.applicationName
30
+
31
+ override fun buildIsolatedComponents(): PlayerComponents {
32
+ return CustomizedPlayerComponents(this)
33
+ }
34
+ }
35
+
36
+ private inner class CustomizedPlayerComponents(shared: SharedComponents) : DefaultPlayerComponents(shared) {
37
+ override val handleAudioFocus: Boolean
38
+ get() = false
39
+ }
40
+
41
+ private class CustomizedDrmSessionManagerProvider : DefaultDrmSessionManagerProvider() {
42
+ override fun buildDrmSessionManager(
43
+ dataSourceFactory: AuthorizedDataSourceProvider,
44
+ source: Source,
45
+ sourceDrm: SourceDrm
46
+ ): DrmSessionManager? {
47
+ if (sourceDrm is SourceDrmOverridden) {
48
+ return buildDrmOverridden(dataSourceFactory, sourceDrm)
49
+ } else {
50
+ return super.buildDrmSessionManager(dataSourceFactory, source, sourceDrm)
51
+ }
52
+ }
53
+
54
+ private fun buildDrmOverridden(dataSourceFactory: AuthorizedDataSourceProvider, sourceDrm: SourceDrmOverridden): DrmSessionManager? {
55
+ val drmUuid = when (sourceDrm.packageName) {
56
+ DrmWidevine.packageName -> C.WIDEVINE_UUID
57
+ DrmPlayready.packageName -> C.PLAYREADY_UUID
58
+ else -> C.UUID_NIL
59
+ }
60
+ val licenseUrl = sourceDrm.licenseServer?.toString() ?: ""
61
+ val forceLicenseUrl = sourceDrm.forceLicenseServer
62
+ val httpDataSourceFactory = dataSourceFactory.buildHttpDataSourceFactory(sourceDrm.authorization)
63
+
64
+ val drmCallback = LoggingDrmCallback(
65
+ OverriddenHttpMediaDrmCallback(
66
+ licenseUrl,
67
+ forceLicenseUrl,
68
+ httpDataSourceFactory
69
+ ),
70
+ licenseUrl
71
+ )
72
+
73
+ return DefaultDrmSessionManager.Builder()
74
+ .setUuidAndExoMediaDrmProvider(drmUuid, FrameworkMediaDrm.DEFAULT_PROVIDER)
75
+ .setMultiSession(false)
76
+ .build(drmCallback)
77
+ }
78
+
79
+ override fun buildDrmCallback(licenseUrl: String, forceLicenseUrl: Boolean, httpDataSourceFactory: HttpDataSource.Factory): MediaDrmCallback {
80
+ return LoggingDrmCallback(super.buildDrmCallback(licenseUrl, forceLicenseUrl, httpDataSourceFactory), licenseUrl)
81
+ }
82
+ }
83
+ }
84
+
@@ -0,0 +1,32 @@
1
+ package com.twentyfouri.tvbridge.global.utils
2
+
3
+ import android.app.Activity
4
+ import android.app.Application.ActivityLifecycleCallbacks
5
+ import android.os.Bundle
6
+
7
+ abstract class SimpleActivityLifecycleCallback : ActivityLifecycleCallbacks {
8
+
9
+ override fun onActivityStarted(activity: Activity) {
10
+ //Do nothing
11
+ }
12
+
13
+ override fun onActivityResumed(activity: Activity) {
14
+ //Do nothing
15
+ }
16
+
17
+ override fun onActivityPaused(activity: Activity) {
18
+ //Do nothing
19
+ }
20
+
21
+ override fun onActivityStopped(activity: Activity) {
22
+ //Do nothing
23
+ }
24
+
25
+ override fun onActivitySaveInstanceState(activity: Activity, bundle: Bundle) {
26
+ //Do nothing
27
+ }
28
+
29
+ override fun onActivityDestroyed(activity: Activity) {
30
+ //Do nothing
31
+ }
32
+ }
@@ -0,0 +1,49 @@
1
+ package com.twentyfouri.tvbridge.global.utils
2
+
3
+ import com.twentyfouri.player.base.SourceAuthorization
4
+ import com.twentyfouri.player.base.SourceDrm
5
+ import java.net.URI
6
+
7
+ open class SourceDrmOverridden protected constructor(
8
+ builder: Builder
9
+ ) : SourceDrm() {
10
+
11
+ override val packageName: String = builder.packageName
12
+ ?: throw IllegalStateException("Missing SourceDrmOverridden.packageName")
13
+ val licenseServer: URI? = builder.licenseServer
14
+ val forceLicenseServer: Boolean = builder.forceLicenseServer
15
+ val authorization: SourceAuthorization? = builder.authorization
16
+
17
+ override fun hashCode(): Int = licenseServer.hashCode()
18
+
19
+ override fun toString(): String = "SourceDrmOverridden($licenseServer)"
20
+
21
+ override fun equals(other: Any?): Boolean = other is SourceDrmOverridden &&
22
+ packageName == other.packageName &&
23
+ licenseServer == other.licenseServer &&
24
+ forceLicenseServer == other.forceLicenseServer &&
25
+ authorization == other.authorization
26
+
27
+ override fun buildUpon() = Builder()
28
+ .also { it.applyFrom(this) }
29
+
30
+ open class Builder : SourceDrm.Builder() {
31
+ var packageName: String? = null
32
+ var licenseServer: URI? = null
33
+ var forceLicenseServer: Boolean = false
34
+ var authorization: SourceAuthorization? = null
35
+
36
+ open fun applyFrom(source: SourceDrmOverridden) {
37
+ packageName = source.packageName
38
+ licenseServer = source.licenseServer
39
+ forceLicenseServer = source.forceLicenseServer
40
+ authorization = source.authorization
41
+ }
42
+
43
+ override fun build() =
44
+ SourceDrmOverridden(this)
45
+ }
46
+ }
47
+
48
+ inline fun SourceDrmOverridden(block: SourceDrmOverridden.Builder.() -> Unit) =
49
+ SourceDrmOverridden.Builder().apply(block).build()
@@ -0,0 +1,211 @@
1
+ package com.twentyfouri.tvbridge.jump
2
+
3
+ import android.util.Log
4
+ import com.google.android.exoplayer2.ExoPlayer
5
+ import com.google.android.exoplayer2.SimpleExoPlayer
6
+ import com.google.gson.JsonObject
7
+ import com.twentyfouri.tvbridge.BuildConfig
8
+ import com.twentyfouri.tvbridge.webview.model.AnalyticsPlaybackInfo
9
+ import jump.JumpKit
10
+ import jump.insights.models.contextinformation.*
11
+ import jump.insights.models.track.events.JKContentType
12
+ import jump.insights.models.track.events.JKTransactionType
13
+ import jump.libs.gson.annotations.SerializedName
14
+ import java.util.*
15
+
16
+ class JumpAnalytics {
17
+
18
+ private var started = false
19
+ private var hasContent = false
20
+
21
+ fun setPlaybackInfo(playbackInfo: AnalyticsPlaybackInfo) {
22
+ setApplicationId(playbackInfo.id ?: return)
23
+ setUserInfo(playbackInfo.userInfo)
24
+ setContentInfo(playbackInfo.contentInfo)
25
+ }
26
+
27
+ private fun setApplicationId(applicationId: String) {
28
+ if (started) return
29
+ started = true
30
+ JumpKit.setDebugMode(BuildConfig.DEBUG)
31
+ JumpKit.start(applicationId)
32
+ }
33
+
34
+ private fun setUserInfo(params: JsonObject?) {
35
+ JumpKit.insights.setUserInfo(parseUserInfo(params))
36
+ }
37
+
38
+ private fun setContentInfo(params: JsonObject?) {
39
+ val contentInfo = parseContentInfo(params)
40
+ jump.exoplayerextension.JumpKit.insights.setContentInfo(contentInfo)
41
+ hasContent = true
42
+ }
43
+
44
+ fun setVideoPlayer(player: ExoPlayer?) {
45
+ @Suppress("DEPRECATION")
46
+ if (player !is SimpleExoPlayer) {
47
+ /* NOTICE: passing null also causes insights.setContentInfo(null) */
48
+ jump.exoplayerextension.JumpKit.insights.setVideoPlayer(null)
49
+ hasContent = false
50
+ } else if (started && hasContent) {
51
+ jump.exoplayerextension.JumpKit.insights.setVideoPlayer(player)
52
+ } else if (started) {
53
+ Log.w("JumpAnalytics", "No content data available. Did you call SetPlaybackInfo before SetVideoPath?")
54
+ }
55
+ }
56
+
57
+ private fun parseUserInfo(params: JsonObject?): JKUserInfo {
58
+ return try {
59
+ var userType = parseEnum(params, "userType", JKUserType::class.java)
60
+ if (userType == null) userType = JKUserType.ANONYMOUS
61
+ val userId = parseString(params, "userId")
62
+ val userCountry = parseString(params, "userCountry")
63
+ val userBirthDate = parseString(params, "userBirthDate")
64
+ var userSex = parseEnum(params, "userSex", JKUserSex::class.java)
65
+ if (userSex == null) userSex = JKUserSex.UNDEFINED
66
+ val userProfileId = parseString(params, "userProfileId")
67
+ val userOperator = parseString(params, "userOperator")
68
+ if (userType == JKUserType.ANONYMOUS) JKUserInfo.anonymousInstance() else JKUserInfo(userType, userId, userCountry, userBirthDate, userSex, userProfileId, userOperator)
69
+ } catch (e: Exception) {
70
+ Log.w("JumpAnalytics", "Parsing userInfo failed. Falling back to ANONYMOUS", e)
71
+ JKUserInfo.anonymousInstance()
72
+ }
73
+ }
74
+
75
+ private fun parseCategory(params: JsonObject?, property: String): JKContextCategory? {
76
+ val jsonValue = params?.get(property) ?: return null
77
+ return if (!jsonValue.isJsonObject) null else parseCategory(jsonValue.asJsonObject)
78
+ }
79
+
80
+ private fun parseCategory(params: JsonObject): JKContextCategory {
81
+ return JKContextCategory(
82
+ parseString(params, "categoryId"),
83
+ parseString(params, "categoryName")
84
+ )
85
+ }
86
+
87
+ private fun parseSubCategory(params: JsonObject?, property: String): JKContextSubcategory? {
88
+ val jsonValue = params?.get(property) ?: return null
89
+ return if (!jsonValue.isJsonObject) null else parseSubCategory(jsonValue.asJsonObject)
90
+ }
91
+
92
+ private fun parseSubCategory(params: JsonObject): JKContextSubcategory {
93
+ return JKContextSubcategory(
94
+ parseString(params, "subcategoryId"),
95
+ parseString(params, "categoryId"),
96
+ parseString(params, "subcategoryName")
97
+ )
98
+ }
99
+
100
+ private fun parseGenre(params: JsonObject): JKContextGenre {
101
+ return JKContextGenre(
102
+ parseString(params, "genreId"),
103
+ parseString(params, "genreName"),
104
+ parseCategory(params, "categoryId"),
105
+ parseSubCategory(params, "subCategoryId")
106
+ )
107
+ }
108
+
109
+ private fun parseContentInfo(params: JsonObject?): JKContextContent {
110
+ return JKContextContent(
111
+ parseString(params, "contentId"),
112
+ parseString(params, "contentTitle"),
113
+ parseString(params, "contentSerieTitle"),
114
+ parseInteger(params, "contentEpisodeNumber"),
115
+ parseInteger(params, "contentSeasonNumber"),
116
+ parseString(params, "contentDescription"),
117
+ parseCategory(params, "contentCategory"),
118
+ parseSubCategory(params, "contentSubCategory"),
119
+ parseGenres(params, "contentGenres"),
120
+ parseString(params, "contentProvider"),
121
+ parseEnum(params, "contentTransactionType", JKTransactionType::class.java),
122
+ parseEnum(params, "contentType", JKContentType::class.java),
123
+ parseString(params, "contentLanguage")
124
+ )
125
+ }
126
+
127
+ private fun parseGenres(container: JsonObject?, property: String): List<JKContextGenre>? {
128
+ if (container == null) return null
129
+ val jsonValue = container[property] ?: return null
130
+ if (!jsonValue.isJsonArray) return null
131
+ val list = ArrayList<JKContextGenre>()
132
+ for (jsonElement in jsonValue.asJsonArray) {
133
+ if (!jsonElement.isJsonObject) continue
134
+ list.add(parseGenre(jsonElement.asJsonObject))
135
+ }
136
+ return list
137
+ }
138
+
139
+ private fun <T : Enum<T>> parseEnum(container: JsonObject?, property: String, type: Class<T>): T? {
140
+ if (container == null) return null
141
+ val jsonValue = container[property] ?: return null
142
+ if (!jsonValue.isJsonPrimitive) return null
143
+ val primitive = jsonValue.asJsonPrimitive
144
+ return when {
145
+ primitive.isString ->
146
+ parseEnum(type, jsonValue.asString)
147
+ primitive.isNumber ->
148
+ parseEnum(type, jsonValue.asInt)
149
+ else ->
150
+ null
151
+ }
152
+ }
153
+
154
+ private fun <T : Enum<T>> parseEnum(type: Class<T>, value: String): T? {
155
+ try {
156
+ for (constant in type.enumConstants ?: return null) {
157
+ val name = constant.name
158
+ if (name == value) {
159
+ return constant
160
+ }
161
+ val annotation = type.getField(name).getAnnotation(SerializedName::class.java)
162
+ if (annotation != null) {
163
+ if (annotation.value == value) {
164
+ return constant
165
+ }
166
+ }
167
+ }
168
+ return null
169
+ } catch (e: NoSuchFieldException) {
170
+ return null
171
+ }
172
+ }
173
+
174
+ @Suppress("UNCHECKED_CAST")
175
+ private fun <T : Enum<T>> parseEnum(type: Class<T>, value: Int): T? {
176
+ return try {
177
+ val map = type.getDeclaredField("mapper")[null] as Map<T, Int>
178
+ for ((key, value1) in map) {
179
+ if (value1 == value) {
180
+ return key
181
+ }
182
+ }
183
+ null
184
+ } catch (e: ClassCastException) {
185
+ null
186
+ } catch (e: IllegalAccessException) {
187
+ null
188
+ } catch (e: NoSuchFieldException) {
189
+ null
190
+ }
191
+ }
192
+
193
+ private fun parseString(container: JsonObject?, property: String): String? {
194
+ if (container == null) return null
195
+ var jsonValue = container[property]
196
+ if (jsonValue == null && property.endsWith("Id")) {
197
+ // inconsistencies in SDK cause confusion, try uppercased xxxxID just in case
198
+ jsonValue = container[property.replace("Id", "ID")]
199
+ }
200
+ if (jsonValue == null) return null
201
+ if (!jsonValue.isJsonPrimitive) return null
202
+ return if (!jsonValue.asJsonPrimitive.isString) null else jsonValue.asString
203
+ }
204
+
205
+ private fun parseInteger(container: JsonObject?, property: String): Int? {
206
+ if (container == null) return null
207
+ val jsonValue = container[property] ?: return null
208
+ if (!jsonValue.isJsonPrimitive) return null
209
+ return if (!jsonValue.asJsonPrimitive.isNumber) null else jsonValue.asInt
210
+ }
211
+ }