mirror of
https://github.com/lizongying/my-tv.git
synced 2026-10-29 23:56:29 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b075a7db81 | ||
|
|
7821e8fa58 | ||
|
|
3109a61bcf | ||
|
|
ce6e5b6546 | ||
|
|
230e4fea2b | ||
|
|
0d26912321 | ||
|
|
af9ff5c8dd | ||
|
|
f0f43e0fda |
@@ -33,6 +33,9 @@ jobs:
|
|||||||
signingKeyBase64: ${{ secrets.KEYSTORE }}
|
signingKeyBase64: ${{ secrets.KEYSTORE }}
|
||||||
keyStorePassword: ${{ secrets.KEYSTORE_PASSWORD }}
|
keyStorePassword: ${{ secrets.KEYSTORE_PASSWORD }}
|
||||||
keyPassword: ${{ secrets.ALIAS_PASSWORD }}
|
keyPassword: ${{ secrets.ALIAS_PASSWORD }}
|
||||||
|
env:
|
||||||
|
# override default build-tools version (29.0.3) -- optional
|
||||||
|
BUILD_TOOLS_VERSION: "34.0.0"
|
||||||
|
|
||||||
- name: Create Release
|
- name: Create Release
|
||||||
id: create_release
|
id: create_release
|
||||||
|
|||||||
+6
-3
@@ -100,10 +100,13 @@ dependencies {
|
|||||||
// For HLS playback support with ExoPlayer
|
// For HLS playback support with ExoPlayer
|
||||||
implementation "androidx.media3:media3-exoplayer-hls:$media3_version"
|
implementation "androidx.media3:media3-exoplayer-hls:$media3_version"
|
||||||
|
|
||||||
|
// 21:2.9.0 17:2.6.4
|
||||||
|
def retrofit2_version = "2.9.0"
|
||||||
|
|
||||||
implementation 'com.google.protobuf:protobuf-kotlin:3.25.1'
|
implementation 'com.google.protobuf:protobuf-kotlin:3.25.1'
|
||||||
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
|
implementation "com.squareup.retrofit2:converter-gson:$retrofit2_version"
|
||||||
implementation 'com.squareup.retrofit2:converter-protobuf:2.9.0'
|
implementation "com.squareup.retrofit2:converter-protobuf:$retrofit2_version"
|
||||||
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
|
implementation "com.squareup.retrofit2:retrofit:$retrofit2_version"
|
||||||
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.2"
|
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.2"
|
||||||
implementation 'androidx.core:core-ktx:1.11.0-beta02'
|
implementation 'androidx.core:core-ktx:1.11.0-beta02'
|
||||||
implementation 'androidx.leanback:leanback:1.2.0-alpha02'
|
implementation 'androidx.leanback:leanback:1.2.0-alpha02'
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -5,6 +5,7 @@ import android.content.pm.PackageInfo
|
|||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.content.pm.Signature
|
import android.content.pm.Signature
|
||||||
import android.content.pm.SigningInfo
|
import android.content.pm.SigningInfo
|
||||||
|
import android.graphics.Color
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
@@ -36,7 +37,7 @@ class MainActivity : FragmentActivity() {
|
|||||||
private lateinit var gestureDetector: GestureDetector
|
private lateinit var gestureDetector: GestureDetector
|
||||||
|
|
||||||
private val handler = Handler()
|
private val handler = Handler()
|
||||||
private val delay: Long = 3000
|
private val delay: Long = 4000
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
@@ -170,6 +171,40 @@ class MainActivity : FragmentActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun showHelp() {
|
||||||
|
val versionName = getPackageInfo().versionName
|
||||||
|
|
||||||
|
val textView = TextView(this)
|
||||||
|
textView.text =
|
||||||
|
"当前版本: $versionName\n获取最新: https://github.com/lizongying/my-tv/releases/"
|
||||||
|
textView.setBackgroundColor(0xFF263238.toInt())
|
||||||
|
textView.setPadding(20, 50, 20, 20)
|
||||||
|
|
||||||
|
val imageView = ImageView(this)
|
||||||
|
val drawable = ContextCompat.getDrawable(this, R.drawable.appreciate)
|
||||||
|
imageView.setImageDrawable(drawable)
|
||||||
|
imageView.setBackgroundColor(Color.WHITE)
|
||||||
|
|
||||||
|
val linearLayout = LinearLayout(this)
|
||||||
|
linearLayout.orientation = LinearLayout.VERTICAL
|
||||||
|
linearLayout.addView(textView)
|
||||||
|
linearLayout.addView(imageView)
|
||||||
|
|
||||||
|
val layoutParams = LinearLayout.LayoutParams(
|
||||||
|
LinearLayout.LayoutParams.MATCH_PARENT,
|
||||||
|
LinearLayout.LayoutParams.WRAP_CONTENT
|
||||||
|
)
|
||||||
|
imageView.layoutParams = layoutParams
|
||||||
|
textView.layoutParams = layoutParams
|
||||||
|
|
||||||
|
val builder: AlertDialog.Builder = AlertDialog.Builder(this)
|
||||||
|
builder
|
||||||
|
.setView(linearLayout)
|
||||||
|
|
||||||
|
val dialog: AlertDialog = builder.create()
|
||||||
|
dialog.show()
|
||||||
|
}
|
||||||
|
|
||||||
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
|
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
|
||||||
when (keyCode) {
|
when (keyCode) {
|
||||||
KeyEvent.KEYCODE_BACK -> {
|
KeyEvent.KEYCODE_BACK -> {
|
||||||
@@ -192,35 +227,13 @@ class MainActivity : FragmentActivity() {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KeyEvent.KEYCODE_SETTINGS -> {
|
||||||
|
showHelp()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
KeyEvent.KEYCODE_MENU -> {
|
KeyEvent.KEYCODE_MENU -> {
|
||||||
val versionName = getPackageInfo().versionName
|
showHelp()
|
||||||
|
|
||||||
val textView = TextView(this)
|
|
||||||
textView.text =
|
|
||||||
"当前版本: $versionName\n获取最新: https://github.com/lizongying/my-tv/releases/"
|
|
||||||
|
|
||||||
val imageView = ImageView(this)
|
|
||||||
val drawable = ContextCompat.getDrawable(this, R.drawable.appreciate)
|
|
||||||
imageView.setImageDrawable(drawable)
|
|
||||||
|
|
||||||
val linearLayout = LinearLayout(this)
|
|
||||||
linearLayout.orientation = LinearLayout.VERTICAL
|
|
||||||
linearLayout.addView(textView)
|
|
||||||
linearLayout.addView(imageView)
|
|
||||||
|
|
||||||
val layoutParams = LinearLayout.LayoutParams(
|
|
||||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
|
||||||
LinearLayout.LayoutParams.WRAP_CONTENT
|
|
||||||
)
|
|
||||||
imageView.layoutParams = layoutParams
|
|
||||||
textView.layoutParams = layoutParams
|
|
||||||
|
|
||||||
val builder: AlertDialog.Builder = AlertDialog.Builder(this)
|
|
||||||
builder
|
|
||||||
.setView(linearLayout)
|
|
||||||
|
|
||||||
val dialog: AlertDialog = builder.create()
|
|
||||||
dialog.show()
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ class PlayerFragment : Fragment() {
|
|||||||
private var _binding: PlayerBinding? = null
|
private var _binding: PlayerBinding? = null
|
||||||
private var playerView: PlayerView? = null
|
private var playerView: PlayerView? = null
|
||||||
private var tvViewModel: TVViewModel? = null
|
private var tvViewModel: TVViewModel? = null
|
||||||
|
private val aspectRatio = 16f / 9f
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater, container: ViewGroup?,
|
inflater: LayoutInflater, container: ViewGroup?,
|
||||||
@@ -43,10 +44,9 @@ class PlayerFragment : Fragment() {
|
|||||||
playerView!!.player?.playWhenReady = true
|
playerView!!.player?.playWhenReady = true
|
||||||
playerView!!.player?.addListener(object : Player.Listener {
|
playerView!!.player?.addListener(object : Player.Listener {
|
||||||
override fun onVideoSizeChanged(videoSize: VideoSize) {
|
override fun onVideoSizeChanged(videoSize: VideoSize) {
|
||||||
val aspectRatio = 16f / 9f
|
|
||||||
val layoutParams = playerView?.layoutParams
|
|
||||||
val ratio = playerView?.measuredWidth?.div(playerView?.measuredHeight!!)
|
val ratio = playerView?.measuredWidth?.div(playerView?.measuredHeight!!)
|
||||||
if (ratio != null) {
|
if (ratio != null) {
|
||||||
|
val layoutParams = playerView?.layoutParams
|
||||||
if (ratio < aspectRatio) {
|
if (ratio < aspectRatio) {
|
||||||
layoutParams?.height =
|
layoutParams?.height =
|
||||||
(playerView?.measuredWidth?.div(aspectRatio))?.toInt()
|
(playerView?.measuredWidth?.div(aspectRatio))?.toInt()
|
||||||
|
|||||||
@@ -7,11 +7,9 @@ import android.util.Base64
|
|||||||
import android.util.Log
|
import android.util.Log
|
||||||
import com.lizongying.mytv.Utils.getDateFormat
|
import com.lizongying.mytv.Utils.getDateFormat
|
||||||
import com.lizongying.mytv.api.ApiClient
|
import com.lizongying.mytv.api.ApiClient
|
||||||
import com.lizongying.mytv.api.BtraceClient
|
|
||||||
import com.lizongying.mytv.api.Info
|
import com.lizongying.mytv.api.Info
|
||||||
import com.lizongying.mytv.api.LiveInfo
|
import com.lizongying.mytv.api.LiveInfo
|
||||||
import com.lizongying.mytv.api.LiveInfoRequest
|
import com.lizongying.mytv.api.LiveInfoRequest
|
||||||
import com.lizongying.mytv.api.ProtoClient
|
|
||||||
import com.lizongying.mytv.api.YSP
|
import com.lizongying.mytv.api.YSP
|
||||||
import com.lizongying.mytv.api.YSPApiService
|
import com.lizongying.mytv.api.YSPApiService
|
||||||
import com.lizongying.mytv.api.YSPBtraceService
|
import com.lizongying.mytv.api.YSPBtraceService
|
||||||
@@ -31,8 +29,8 @@ import javax.crypto.spec.SecretKeySpec
|
|||||||
class Request {
|
class Request {
|
||||||
private var yspTokenService: YSPTokenService = ApiClient().yspTokenService
|
private var yspTokenService: YSPTokenService = ApiClient().yspTokenService
|
||||||
private var yspApiService: YSPApiService = ApiClient().yspApiService
|
private var yspApiService: YSPApiService = ApiClient().yspApiService
|
||||||
private var yspBtraceService: YSPBtraceService = BtraceClient().yspBtraceService
|
private var yspBtraceService: YSPBtraceService = ApiClient().yspBtraceService
|
||||||
private var yspProtoService: YSPProtoService = ProtoClient().yspProtoService
|
private var yspProtoService: YSPProtoService = ApiClient().yspProtoService
|
||||||
private var ysp: YSP? = null
|
private var ysp: YSP? = null
|
||||||
|
|
||||||
// TODO onDestroy
|
// TODO onDestroy
|
||||||
@@ -62,7 +60,6 @@ class Request {
|
|||||||
"CGTN阿拉伯语频道" to "CGTN 阿拉伯语频道",
|
"CGTN阿拉伯语频道" to "CGTN 阿拉伯语频道",
|
||||||
"CGTN西班牙语频道" to "CGTN 西班牙语频道",
|
"CGTN西班牙语频道" to "CGTN 西班牙语频道",
|
||||||
"CGTN外语纪录频道" to "CGTN 纪录频道",
|
"CGTN外语纪录频道" to "CGTN 纪录频道",
|
||||||
|
|
||||||
"东方卫视" to "东方卫视",
|
"东方卫视" to "东方卫视",
|
||||||
"湖南卫视" to "湖南卫视",
|
"湖南卫视" to "湖南卫视",
|
||||||
"湖北卫视" to "湖北卫视",
|
"湖北卫视" to "湖北卫视",
|
||||||
@@ -90,7 +87,10 @@ class Request {
|
|||||||
ysp = YSP(context)
|
ysp = YSP(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var call: Call<LiveInfo>? = null
|
||||||
|
|
||||||
fun fetchVideo(tvModel: TVViewModel, cookie: String) {
|
fun fetchVideo(tvModel: TVViewModel, cookie: String) {
|
||||||
|
call?.cancel()
|
||||||
if (::myRunnable.isInitialized) {
|
if (::myRunnable.isInitialized) {
|
||||||
handler.removeCallbacks(myRunnable)
|
handler.removeCallbacks(myRunnable)
|
||||||
}
|
}
|
||||||
@@ -100,71 +100,71 @@ class Request {
|
|||||||
tvModel.seq = 0
|
tvModel.seq = 0
|
||||||
val data = ysp?.switch(tvModel)
|
val data = ysp?.switch(tvModel)
|
||||||
val request = data?.let { LiveInfoRequest(it) }
|
val request = data?.let { LiveInfoRequest(it) }
|
||||||
|
call = request?.let { yspApiService.getLiveInfo("guid=${ysp?.getGuid()}; $cookie", it) }
|
||||||
|
|
||||||
request?.let { yspApiService.getLiveInfo(cookie, it) }
|
call?.enqueue(object : Callback<LiveInfo> {
|
||||||
?.enqueue(object : Callback<LiveInfo> {
|
override fun onResponse(call: Call<LiveInfo>, response: Response<LiveInfo>) {
|
||||||
override fun onResponse(call: Call<LiveInfo>, response: Response<LiveInfo>) {
|
if (response.isSuccessful) {
|
||||||
if (response.isSuccessful) {
|
val liveInfo = response.body()
|
||||||
val liveInfo = response.body()
|
if (liveInfo?.data?.playurl != null) {
|
||||||
if (liveInfo?.data?.playurl != null) {
|
val chanll = liveInfo.data.chanll
|
||||||
val chanll = liveInfo.data.chanll
|
val decodedBytes = Base64.decode(
|
||||||
val decodedBytes = Base64.decode(
|
chanll.substring(9, chanll.length - 3),
|
||||||
chanll.substring(9, chanll.length - 3),
|
Base64.DEFAULT
|
||||||
Base64.DEFAULT
|
)
|
||||||
)
|
val decodedString = String(decodedBytes)
|
||||||
val decodedString = String(decodedBytes)
|
val regex = Regex("""des_key = "([^"]+).+var des_iv = "([^"]+)""")
|
||||||
val regex = Regex("""des_key = "([^"]+).+var des_iv = "([^"]+)""")
|
val matchResult = regex.find(decodedString)
|
||||||
val matchResult = regex.find(decodedString)
|
if (matchResult != null) {
|
||||||
if (matchResult != null) {
|
val (key, iv) = matchResult.destructured
|
||||||
val (key, iv) = matchResult.destructured
|
val keyBytes = Base64.decode(key, Base64.DEFAULT)
|
||||||
val keyBytes = Base64.decode(key, Base64.DEFAULT)
|
val ivBytes = Base64.decode(iv, Base64.DEFAULT)
|
||||||
val ivBytes = Base64.decode(iv, Base64.DEFAULT)
|
val url = liveInfo.data.playurl + "&revoi=" + encryptTripleDES(
|
||||||
val url = liveInfo.data.playurl + "&revoi=" + encryptTripleDES(
|
keyBytes + byteArrayOf(0, 0, 0, 0, 0, 0, 0, 0),
|
||||||
keyBytes + byteArrayOf(0, 0, 0, 0, 0, 0, 0, 0),
|
ivBytes
|
||||||
ivBytes
|
).uppercase()
|
||||||
).uppercase()
|
Log.i(TAG, "$title url $url")
|
||||||
Log.i(TAG, "$title url $url")
|
tvModel.addVideoUrl(url)
|
||||||
tvModel.addVideoUrl(url)
|
tvModel.allReady()
|
||||||
tvModel.allReady()
|
tvModel.retryTimes = 0
|
||||||
tvModel.retryTimes = 0
|
myRunnable = MyRunnable(tvModel)
|
||||||
myRunnable = MyRunnable(tvModel)
|
handler.post(myRunnable)
|
||||||
handler.post(myRunnable)
|
|
||||||
} else {
|
|
||||||
Log.e(TAG, "$title key error")
|
|
||||||
if (tvModel.retryTimes < tvModel.retryMaxTimes) {
|
|
||||||
tvModel.retryTimes++
|
|
||||||
fetchVideo(tvModel, cookie)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (liveInfo?.data?.errinfo != null && liveInfo.data.errinfo != "success!") {
|
Log.e(TAG, "$title key error")
|
||||||
Log.e(TAG, "$title url error ${liveInfo.data.errinfo}")
|
if (tvModel.retryTimes < tvModel.retryMaxTimes) {
|
||||||
tvModel.setErrInfo(liveInfo.data.errinfo)
|
tvModel.retryTimes++
|
||||||
} else {
|
fetchVideo(tvModel, cookie)
|
||||||
Log.e(TAG, "$title url error $request $liveInfo")
|
|
||||||
if (tvModel.retryTimes < tvModel.retryMaxTimes) {
|
|
||||||
tvModel.retryTimes++
|
|
||||||
fetchVideo(tvModel, cookie)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Log.e(TAG, "$title status error")
|
if (liveInfo?.data?.errinfo != null && liveInfo.data.errinfo == "应版权方要求,暂停提供直播信号,请点击观看其他精彩节目") {
|
||||||
if (tvModel.retryTimes < tvModel.retryMaxTimes) {
|
Log.e(TAG, "$title error ${liveInfo.data.errinfo}")
|
||||||
tvModel.retryTimes++
|
tvModel.setErrInfo(liveInfo.data.errinfo)
|
||||||
fetchVideo(tvModel, cookie)
|
} else {
|
||||||
|
Log.e(TAG, "$title url error $request $liveInfo")
|
||||||
|
if (tvModel.retryTimes < tvModel.retryMaxTimes) {
|
||||||
|
tvModel.retryTimes++
|
||||||
|
fetchVideo(tvModel, cookie)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
|
Log.e(TAG, "$title status error")
|
||||||
override fun onFailure(call: Call<LiveInfo>, t: Throwable) {
|
|
||||||
Log.e(TAG, "$title request error")
|
|
||||||
if (tvModel.retryTimes < tvModel.retryMaxTimes) {
|
if (tvModel.retryTimes < tvModel.retryMaxTimes) {
|
||||||
tvModel.retryTimes++
|
tvModel.retryTimes++
|
||||||
fetchVideo(tvModel, cookie)
|
fetchVideo(tvModel, cookie)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
|
||||||
|
override fun onFailure(call: Call<LiveInfo>, t: Throwable) {
|
||||||
|
Log.e(TAG, "$title request error")
|
||||||
|
if (tvModel.retryTimes < tvModel.retryMaxTimes) {
|
||||||
|
tvModel.retryTimes++
|
||||||
|
fetchVideo(tvModel, cookie)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fun fetchVideo(tvModel: TVViewModel) {
|
fun fetchVideo(tvModel: TVViewModel) {
|
||||||
@@ -172,11 +172,10 @@ class Request {
|
|||||||
.enqueue(object : Callback<Info> {
|
.enqueue(object : Callback<Info> {
|
||||||
override fun onResponse(call: Call<Info>, response: Response<Info>) {
|
override fun onResponse(call: Call<Info>, response: Response<Info>) {
|
||||||
if (response.isSuccessful) {
|
if (response.isSuccessful) {
|
||||||
val info = response.body()
|
val token = response.body()?.data?.token
|
||||||
val token = info?.data?.token
|
|
||||||
Log.i(TAG, "info success $token")
|
Log.i(TAG, "info success $token")
|
||||||
val cookie =
|
val cookie =
|
||||||
"guid=1; vplatform=109; yspopenid=vu0-8lgGV2LW9QjDeuBFsX8yMnzs37Q3_HZF6XyVDpGR_I; vusession=$token"
|
"vplatform=109; yspopenid=vu0-8lgGV2LW9QjDeuBFsX8yMnzs37Q3_HZF6XyVDpGR_I; vusession=$token"
|
||||||
fetchVideo(tvModel, cookie)
|
fetchVideo(tvModel, cookie)
|
||||||
} else {
|
} else {
|
||||||
Log.e(TAG, "info status error")
|
Log.e(TAG, "info status error")
|
||||||
@@ -201,7 +200,7 @@ class Request {
|
|||||||
if (tvModel.needToken) {
|
if (tvModel.needToken) {
|
||||||
fetchVideo(tvModel)
|
fetchVideo(tvModel)
|
||||||
} else {
|
} else {
|
||||||
val cookie = "guid=1; vplatform=109"
|
val cookie = "vplatform=109"
|
||||||
fetchVideo(tvModel, cookie)
|
fetchVideo(tvModel, cookie)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,27 @@
|
|||||||
package com.lizongying.mytv.api
|
package com.lizongying.mytv.api
|
||||||
|
|
||||||
|
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
import retrofit2.Retrofit
|
import retrofit2.Retrofit
|
||||||
import retrofit2.converter.gson.GsonConverterFactory
|
import retrofit2.converter.gson.GsonConverterFactory
|
||||||
|
import retrofit2.converter.protobuf.ProtoConverterFactory
|
||||||
|
import javax.net.ssl.SSLContext
|
||||||
|
import javax.net.ssl.TrustManager
|
||||||
|
import javax.net.ssl.X509TrustManager
|
||||||
|
|
||||||
|
|
||||||
class ApiClient {
|
class ApiClient {
|
||||||
private val yspUrl = "https://player-api.yangshipin.cn/"
|
private val yspUrl = "https://player-api.yangshipin.cn/"
|
||||||
private val myUrl = "https://lyrics.run/"
|
private val myUrl = "https://lyrics.run/"
|
||||||
// private val myUrl = "http://10.0.2.2:8081/"
|
private val protoUrl = "https://capi.yangshipin.cn/"
|
||||||
|
private val traceUrl = "https://btrace.yangshipin.cn/"
|
||||||
|
|
||||||
|
private var okHttpClient = getUnsafeOkHttpClient()
|
||||||
|
|
||||||
val yspApiService: YSPApiService by lazy {
|
val yspApiService: YSPApiService by lazy {
|
||||||
Retrofit.Builder()
|
Retrofit.Builder()
|
||||||
.baseUrl(yspUrl)
|
.baseUrl(yspUrl)
|
||||||
|
.client(okHttpClient)
|
||||||
.addConverterFactory(GsonConverterFactory.create())
|
.addConverterFactory(GsonConverterFactory.create())
|
||||||
.build().create(YSPApiService::class.java)
|
.build().create(YSPApiService::class.java)
|
||||||
}
|
}
|
||||||
@@ -20,7 +29,60 @@ class ApiClient {
|
|||||||
val yspTokenService: YSPTokenService by lazy {
|
val yspTokenService: YSPTokenService by lazy {
|
||||||
Retrofit.Builder()
|
Retrofit.Builder()
|
||||||
.baseUrl(myUrl)
|
.baseUrl(myUrl)
|
||||||
|
.client(okHttpClient)
|
||||||
.addConverterFactory(GsonConverterFactory.create())
|
.addConverterFactory(GsonConverterFactory.create())
|
||||||
.build().create(YSPTokenService::class.java)
|
.build().create(YSPTokenService::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val yspProtoService: YSPProtoService by lazy {
|
||||||
|
Retrofit.Builder()
|
||||||
|
.baseUrl(protoUrl)
|
||||||
|
.client(okHttpClient)
|
||||||
|
.addConverterFactory(ProtoConverterFactory.create())
|
||||||
|
.build().create(YSPProtoService::class.java)
|
||||||
|
}
|
||||||
|
|
||||||
|
val yspBtraceService: YSPBtraceService by lazy {
|
||||||
|
Retrofit.Builder()
|
||||||
|
.baseUrl(traceUrl)
|
||||||
|
.client(okHttpClient)
|
||||||
|
.addConverterFactory(GsonConverterFactory.create())
|
||||||
|
.build().create(YSPBtraceService::class.java)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getUnsafeOkHttpClient(): OkHttpClient {
|
||||||
|
try {
|
||||||
|
val trustAllCerts: Array<TrustManager> = arrayOf(
|
||||||
|
object : X509TrustManager {
|
||||||
|
override fun checkClientTrusted(
|
||||||
|
chain: Array<out java.security.cert.X509Certificate>?,
|
||||||
|
authType: String?
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun checkServerTrusted(
|
||||||
|
chain: Array<out java.security.cert.X509Certificate>?,
|
||||||
|
authType: String?
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getAcceptedIssuers(): Array<java.security.cert.X509Certificate> {
|
||||||
|
return emptyArray()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
val sslContext = SSLContext.getInstance("SSL")
|
||||||
|
sslContext.init(null, trustAllCerts, java.security.SecureRandom())
|
||||||
|
|
||||||
|
return OkHttpClient.Builder()
|
||||||
|
.sslSocketFactory(sslContext.socketFactory, trustAllCerts[0] as X509TrustManager)
|
||||||
|
.hostnameVerifier { _, _ -> true }
|
||||||
|
.dns(DnsCache())
|
||||||
|
.build()
|
||||||
|
|
||||||
|
} catch (e: Exception) {
|
||||||
|
throw RuntimeException(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
package com.lizongying.mytv.api
|
|
||||||
|
|
||||||
|
|
||||||
import retrofit2.Retrofit
|
|
||||||
import retrofit2.converter.gson.GsonConverterFactory
|
|
||||||
|
|
||||||
|
|
||||||
class BtraceClient {
|
|
||||||
private val yspUrl = "https://btrace.yangshipin.cn/"
|
|
||||||
|
|
||||||
val yspBtraceService: YSPBtraceService by lazy {
|
|
||||||
Retrofit.Builder()
|
|
||||||
.baseUrl(yspUrl)
|
|
||||||
.addConverterFactory(GsonConverterFactory.create())
|
|
||||||
.build().create(YSPBtraceService::class.java)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package com.lizongying.mytv.api
|
||||||
|
|
||||||
|
import okhttp3.Dns
|
||||||
|
import java.net.InetAddress
|
||||||
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
|
||||||
|
class DnsCache : Dns {
|
||||||
|
private val dnsCache: MutableMap<String, List<InetAddress>> = ConcurrentHashMap()
|
||||||
|
|
||||||
|
override fun lookup(hostname: String): List<InetAddress> {
|
||||||
|
dnsCache[hostname]?.let {
|
||||||
|
return it
|
||||||
|
}
|
||||||
|
|
||||||
|
val addresses = InetAddress.getAllByName(hostname).toList()
|
||||||
|
|
||||||
|
if (addresses.isNotEmpty()) {
|
||||||
|
dnsCache[hostname] = addresses
|
||||||
|
}
|
||||||
|
|
||||||
|
return addresses
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
package com.lizongying.mytv.api
|
|
||||||
|
|
||||||
import retrofit2.Retrofit
|
|
||||||
import retrofit2.converter.protobuf.ProtoConverterFactory
|
|
||||||
|
|
||||||
|
|
||||||
class ProtoClient {
|
|
||||||
private val protoUrl = "https://capi.yangshipin.cn/"
|
|
||||||
|
|
||||||
val yspProtoService: YSPProtoService by lazy {
|
|
||||||
Retrofit.Builder()
|
|
||||||
.baseUrl(protoUrl)
|
|
||||||
.addConverterFactory(ProtoConverterFactory.create())
|
|
||||||
.build().create(YSPProtoService::class.java)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -70,6 +70,11 @@ class YSP(var context: Context) {
|
|||||||
defn = "fhd"
|
defn = "fhd"
|
||||||
|
|
||||||
randStr = getRand()
|
randStr = getRand()
|
||||||
|
|
||||||
|
if (tvModel.retryTimes > 0) {
|
||||||
|
guid = newGuid()
|
||||||
|
}
|
||||||
|
|
||||||
timeStr = getTimeStr()
|
timeStr = getTimeStr()
|
||||||
|
|
||||||
// guid = "lq3oqitm_1e15dnzgjnb"
|
// guid = "lq3oqitm_1e15dnzgjnb"
|
||||||
@@ -105,6 +110,15 @@ class YSP(var context: Context) {
|
|||||||
return guid
|
return guid
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun newGuid(): String {
|
||||||
|
guid = generateGuid()
|
||||||
|
with(sharedPref!!.edit()) {
|
||||||
|
putString("guid", guid)
|
||||||
|
apply()
|
||||||
|
}
|
||||||
|
return guid
|
||||||
|
}
|
||||||
|
|
||||||
fun getRand(): String {
|
fun getRand(): String {
|
||||||
var n = ""
|
var n = ""
|
||||||
val e = "ABCDEFGHIJKlMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
|
val e = "ABCDEFGHIJKlMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package com.lizongying.mytv.models
|
package com.lizongying.mytv.models
|
||||||
|
|
||||||
import android.content.SharedPreferences
|
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ class TVViewModel(private var tv: TV) : ViewModel() {
|
|||||||
private var itemPosition: Int = 0
|
private var itemPosition: Int = 0
|
||||||
|
|
||||||
var retryTimes: Int = 0
|
var retryTimes: Int = 0
|
||||||
var retryMaxTimes: Int = 3
|
var retryMaxTimes: Int = 5
|
||||||
var programUpdateTime: Long = 0
|
var programUpdateTime: Long = 0
|
||||||
|
|
||||||
private val _errInfo = MutableLiveData<String>()
|
private val _errInfo = MutableLiveData<String>()
|
||||||
@@ -71,7 +71,7 @@ class TVViewModel(private var tv: TV) : ViewModel() {
|
|||||||
val ready: LiveData<Boolean>
|
val ready: LiveData<Boolean>
|
||||||
get() = _ready
|
get() = _ready
|
||||||
|
|
||||||
private var mMinimumLoadableRetryCount = 3
|
private var mMinimumLoadableRetryCount = 5
|
||||||
|
|
||||||
var seq = 0
|
var seq = 0
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user