diff --git a/app/src/main/java/com/lizongying/mytv/MainActivity.kt b/app/src/main/java/com/lizongying/mytv/MainActivity.kt index dc4274b..71127a3 100644 --- a/app/src/main/java/com/lizongying/mytv/MainActivity.kt +++ b/app/src/main/java/com/lizongying/mytv/MainActivity.kt @@ -5,6 +5,7 @@ import android.content.pm.PackageInfo import android.content.pm.PackageManager import android.content.pm.Signature import android.content.pm.SigningInfo +import android.graphics.Color import android.os.Build import android.os.Bundle import android.os.Handler @@ -36,7 +37,7 @@ class MainActivity : FragmentActivity() { private lateinit var gestureDetector: GestureDetector private val handler = Handler() - private val delay: Long = 3000 + private val delay: Long = 4000 override fun onCreate(savedInstanceState: Bundle?) { 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 { when (keyCode) { KeyEvent.KEYCODE_BACK -> { @@ -192,35 +227,13 @@ class MainActivity : FragmentActivity() { return true } + KeyEvent.KEYCODE_SETTINGS -> { + showHelp() + return true + } + KeyEvent.KEYCODE_MENU -> { - val versionName = getPackageInfo().versionName - - 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() + showHelp() return true } diff --git a/app/src/main/java/com/lizongying/mytv/Request.kt b/app/src/main/java/com/lizongying/mytv/Request.kt index e408f91..8d18e0f 100644 --- a/app/src/main/java/com/lizongying/mytv/Request.kt +++ b/app/src/main/java/com/lizongying/mytv/Request.kt @@ -87,7 +87,10 @@ class Request { ysp = YSP(context) } + var call: Call? = null + fun fetchVideo(tvModel: TVViewModel, cookie: String) { + call?.cancel() if (::myRunnable.isInitialized) { handler.removeCallbacks(myRunnable) } @@ -97,71 +100,71 @@ class Request { tvModel.seq = 0 val data = ysp?.switch(tvModel) val request = data?.let { LiveInfoRequest(it) } + call = request?.let { yspApiService.getLiveInfo("guid=${ysp?.getGuid()}; $cookie", it) } - request?.let { yspApiService.getLiveInfo(cookie, it) } - ?.enqueue(object : Callback { - override fun onResponse(call: Call, response: Response) { - if (response.isSuccessful) { - val liveInfo = response.body() - if (liveInfo?.data?.playurl != null) { - val chanll = liveInfo.data.chanll - val decodedBytes = Base64.decode( - chanll.substring(9, chanll.length - 3), - Base64.DEFAULT - ) - val decodedString = String(decodedBytes) - val regex = Regex("""des_key = "([^"]+).+var des_iv = "([^"]+)""") - val matchResult = regex.find(decodedString) - if (matchResult != null) { - val (key, iv) = matchResult.destructured - val keyBytes = Base64.decode(key, Base64.DEFAULT) - val ivBytes = Base64.decode(iv, Base64.DEFAULT) - val url = liveInfo.data.playurl + "&revoi=" + encryptTripleDES( - keyBytes + byteArrayOf(0, 0, 0, 0, 0, 0, 0, 0), - ivBytes - ).uppercase() - Log.i(TAG, "$title url $url") - tvModel.addVideoUrl(url) - tvModel.allReady() - tvModel.retryTimes = 0 - myRunnable = MyRunnable(tvModel) - handler.post(myRunnable) - } else { - Log.e(TAG, "$title key error") - if (tvModel.retryTimes < tvModel.retryMaxTimes) { - tvModel.retryTimes++ - fetchVideo(tvModel, cookie) - } - } + call?.enqueue(object : Callback { + override fun onResponse(call: Call, response: Response) { + if (response.isSuccessful) { + val liveInfo = response.body() + if (liveInfo?.data?.playurl != null) { + val chanll = liveInfo.data.chanll + val decodedBytes = Base64.decode( + chanll.substring(9, chanll.length - 3), + Base64.DEFAULT + ) + val decodedString = String(decodedBytes) + val regex = Regex("""des_key = "([^"]+).+var des_iv = "([^"]+)""") + val matchResult = regex.find(decodedString) + if (matchResult != null) { + val (key, iv) = matchResult.destructured + val keyBytes = Base64.decode(key, Base64.DEFAULT) + val ivBytes = Base64.decode(iv, Base64.DEFAULT) + val url = liveInfo.data.playurl + "&revoi=" + encryptTripleDES( + keyBytes + byteArrayOf(0, 0, 0, 0, 0, 0, 0, 0), + ivBytes + ).uppercase() + Log.i(TAG, "$title url $url") + tvModel.addVideoUrl(url) + tvModel.allReady() + tvModel.retryTimes = 0 + myRunnable = MyRunnable(tvModel) + handler.post(myRunnable) } else { - if (liveInfo?.data?.errinfo != null && liveInfo.data.errinfo == "应版权方要求,暂停提供直播信号,请点击观看其他精彩节目") { - Log.e(TAG, "$title error ${liveInfo.data.errinfo}") - tvModel.setErrInfo(liveInfo.data.errinfo) - } else { - Log.e(TAG, "$title url error $request $liveInfo") - if (tvModel.retryTimes < tvModel.retryMaxTimes) { - tvModel.retryTimes++ - fetchVideo(tvModel, cookie) - } + Log.e(TAG, "$title key error") + if (tvModel.retryTimes < tvModel.retryMaxTimes) { + tvModel.retryTimes++ + fetchVideo(tvModel, cookie) } } } else { - Log.e(TAG, "$title status error") - if (tvModel.retryTimes < tvModel.retryMaxTimes) { - tvModel.retryTimes++ - fetchVideo(tvModel, cookie) + if (liveInfo?.data?.errinfo != null && liveInfo.data.errinfo == "应版权方要求,暂停提供直播信号,请点击观看其他精彩节目") { + Log.e(TAG, "$title error ${liveInfo.data.errinfo}") + tvModel.setErrInfo(liveInfo.data.errinfo) + } else { + Log.e(TAG, "$title url error $request $liveInfo") + if (tvModel.retryTimes < tvModel.retryMaxTimes) { + tvModel.retryTimes++ + fetchVideo(tvModel, cookie) + } } } - } - - override fun onFailure(call: Call, t: Throwable) { - Log.e(TAG, "$title request error") + } else { + Log.e(TAG, "$title status error") if (tvModel.retryTimes < tvModel.retryMaxTimes) { tvModel.retryTimes++ fetchVideo(tvModel, cookie) } } - }) + } + + override fun onFailure(call: Call, t: Throwable) { + Log.e(TAG, "$title request error") + if (tvModel.retryTimes < tvModel.retryMaxTimes) { + tvModel.retryTimes++ + fetchVideo(tvModel, cookie) + } + } + }) } fun fetchVideo(tvModel: TVViewModel) { @@ -172,7 +175,7 @@ class Request { val token = response.body()?.data?.token Log.i(TAG, "info success $token") 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) } else { Log.e(TAG, "info status error") @@ -197,7 +200,7 @@ class Request { if (tvModel.needToken) { fetchVideo(tvModel) } else { - val cookie = "guid=1; vplatform=109" + val cookie = "vplatform=109" fetchVideo(tvModel, cookie) } } diff --git a/app/src/main/java/com/lizongying/mytv/api/ApiClient.kt b/app/src/main/java/com/lizongying/mytv/api/ApiClient.kt index 9b01754..076e6aa 100644 --- a/app/src/main/java/com/lizongying/mytv/api/ApiClient.kt +++ b/app/src/main/java/com/lizongying/mytv/api/ApiClient.kt @@ -5,6 +5,9 @@ import okhttp3.OkHttpClient import retrofit2.Retrofit 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 { @@ -13,9 +16,7 @@ class ApiClient { private val protoUrl = "https://capi.yangshipin.cn/" private val traceUrl = "https://btrace.yangshipin.cn/" - private var okHttpClient = OkHttpClient.Builder() - .dns(DnsCache()) - .build() + private var okHttpClient = getUnsafeOkHttpClient() val yspApiService: YSPApiService by lazy { Retrofit.Builder() @@ -48,4 +49,40 @@ class ApiClient { .addConverterFactory(GsonConverterFactory.create()) .build().create(YSPBtraceService::class.java) } + + private fun getUnsafeOkHttpClient(): OkHttpClient { + try { + val trustAllCerts: Array = arrayOf( + object : X509TrustManager { + override fun checkClientTrusted( + chain: Array?, + authType: String? + ) { + } + + override fun checkServerTrusted( + chain: Array?, + authType: String? + ) { + } + + override fun getAcceptedIssuers(): Array { + 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) + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/lizongying/mytv/api/YSP.kt b/app/src/main/java/com/lizongying/mytv/api/YSP.kt index c6bece9..7c0eef7 100644 --- a/app/src/main/java/com/lizongying/mytv/api/YSP.kt +++ b/app/src/main/java/com/lizongying/mytv/api/YSP.kt @@ -71,7 +71,10 @@ class YSP(var context: Context) { randStr = getRand() - guid = newGuid() + if (tvModel.retryTimes > 0) { + guid = newGuid() + } + timeStr = getTimeStr() // guid = "lq3oqitm_1e15dnzgjnb" @@ -107,7 +110,7 @@ class YSP(var context: Context) { return guid } - fun newGuid(): String { + private fun newGuid(): String { guid = generateGuid() with(sharedPref!!.edit()) { putString("guid", guid)