diff --git a/README.md b/README.md index 170ec18..b8477f4 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,10 @@ ### v1.6.3(安卓5及以上专用) * 增加CETV1 +* 凤凰卫视增强画质 * 默认关闭开机启动 +* 延迟菜单自动关闭时间 +* 解决一些可能导致首次打开时黑屏的问题 ### v1.6.2(通用) diff --git a/app/src/main/java/com/lizongying/mytv/MainActivity.kt b/app/src/main/java/com/lizongying/mytv/MainActivity.kt index 41a563f..256607e 100644 --- a/app/src/main/java/com/lizongying/mytv/MainActivity.kt +++ b/app/src/main/java/com/lizongying/mytv/MainActivity.kt @@ -25,7 +25,7 @@ import kotlinx.coroutines.launch import java.security.MessageDigest -class MainActivity : FragmentActivity() { +class MainActivity : FragmentActivity(), Request.RequestListener { private var ready = 0 private var playerFragment = PlayerFragment() @@ -42,21 +42,24 @@ class MainActivity : FragmentActivity() { private val delayHideMain: Long = 10000 private val delayHideSetting: Long = 10000 - init { - lifecycleScope.launch(Dispatchers.IO) { - val utilsJob = async(start = CoroutineStart.LAZY) { Utils.init() } - - utilsJob.start() - - utilsJob.await() - } - } +// init { +// lifecycleScope.launch(Dispatchers.IO) { +// val utilsJob = async(start = CoroutineStart.LAZY) { Utils.init() } +// +// utilsJob.start() +// +// utilsJob.await() +// } +// } override fun onCreate(savedInstanceState: Bundle?) { Log.i(TAG, "onCreate") super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) + Request.onCreate() + Request.setRequestListener(this) + window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN) window.decorView.systemUiVisibility = SYSTEM_UI_FLAG_HIDE_NAVIGATION @@ -78,7 +81,13 @@ class MainActivity : FragmentActivity() { } else { packageInfo.versionCode.toLong() } - settingFragment = SettingFragment(versionName, versionCode, SP.channelReversal, SP.channelNum, SP.bootStartup) + settingFragment = SettingFragment( + versionName, + versionCode, + SP.channelReversal, + SP.channelNum, + SP.bootStartup + ) } fun showInfoFragment(tvViewModel: TVViewModel) { @@ -171,7 +180,7 @@ class MainActivity : FragmentActivity() { fun fragmentReady() { ready++ Log.i(TAG, "ready $ready") - if (ready == 4) { + if (ready == 5) { mainFragment.fragmentReady() } } @@ -507,7 +516,17 @@ class MainActivity : FragmentActivity() { handler.removeCallbacks(hideMain) } + override fun onDestroy() { + super.onDestroy() + Request.onDestroy() + } + + override fun onRequestFinished() { + fragmentReady() + } + private companion object { const val TAG = "MainActivity" } + } \ No newline at end of file diff --git a/app/src/main/java/com/lizongying/mytv/MainFragment.kt b/app/src/main/java/com/lizongying/mytv/MainFragment.kt index 2fff3bf..a571731 100644 --- a/app/src/main/java/com/lizongying/mytv/MainFragment.kt +++ b/app/src/main/java/com/lizongying/mytv/MainFragment.kt @@ -18,6 +18,7 @@ import androidx.leanback.widget.Row import androidx.leanback.widget.RowPresenter import androidx.lifecycle.lifecycleScope import com.lizongying.mytv.Utils.getDateTimestamp +import com.lizongying.mytv.api.YSP import com.lizongying.mytv.models.TVListViewModel import com.lizongying.mytv.models.TVViewModel import kotlinx.coroutines.Dispatchers @@ -29,8 +30,6 @@ class MainFragment : BrowseSupportFragment() { private var rowsAdapter: ArrayObjectAdapter? = null - private var request = Request() - var tvListViewModel = TVListViewModel() private var lastVideoUrl = "" @@ -52,7 +51,7 @@ class MainFragment : BrowseSupportFragment() { override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) - activity?.let { request.initYSP(it) } + activity?.let { YSP.init(it) } loadRows() @@ -87,7 +86,7 @@ class MainFragment : BrowseSupportFragment() { if (tvViewModel.pid.value != "") { Log.i(TAG, "request $title") lifecycleScope.launch(Dispatchers.IO) { - tvViewModel.let { request.fetchData(it) } + tvViewModel.let { Request.fetchData(it) } } (activity as? MainActivity)?.showInfoFragment(tvViewModel) setSelectedPosition( @@ -283,11 +282,11 @@ class MainFragment : BrowseSupportFragment() { if (timestamp - tvViewModel.programUpdateTime > 60) { if (tvViewModel.program.value!!.isEmpty()) { tvViewModel.programUpdateTime = timestamp - request.fetchProgram(tvViewModel) + Request.fetchProgram(tvViewModel) } else { if (tvViewModel.program.value!!.last().et - timestamp < 600) { tvViewModel.programUpdateTime = timestamp - request.fetchProgram(tvViewModel) + Request.fetchProgram(tvViewModel) } } } diff --git a/app/src/main/java/com/lizongying/mytv/Request.kt b/app/src/main/java/com/lizongying/mytv/Request.kt index 95d60bc..a4589a5 100644 --- a/app/src/main/java/com/lizongying/mytv/Request.kt +++ b/app/src/main/java/com/lizongying/mytv/Request.kt @@ -1,6 +1,5 @@ package com.lizongying.mytv -import android.content.Context import android.os.Handler import android.os.Looper import android.util.Base64 @@ -12,6 +11,7 @@ import com.lizongying.mytv.api.AuthRequest import com.lizongying.mytv.api.FAuth import com.lizongying.mytv.api.FAuthService import com.lizongying.mytv.api.Info +import com.lizongying.mytv.api.InfoV2 import com.lizongying.mytv.api.LiveInfo import com.lizongying.mytv.api.LiveInfoRequest import com.lizongying.mytv.api.Token @@ -32,18 +32,19 @@ import javax.crypto.spec.SecretKeySpec import kotlin.math.max -class Request { +object Request { + private const val TAG = "Request" private var yspTokenService: YSPTokenService = ApiClient().yspTokenService private var yspApiService: YSPApiService = ApiClient().yspApiService private var yspBtraceService: YSPBtraceService = ApiClient().yspBtraceService private var yspProtoService: YSPProtoService = ApiClient().yspProtoService private var fAuthService: FAuthService = ApiClient().fAuthService - private var ysp: YSP? = null + private var token = "" + private var tokenFH = "" private var needAuth = false - // TODO onDestroy private val handler = Handler(Looper.getMainLooper()) private lateinit var btraceRunnable: BtraceRunnable private var tokenRunnable: TokenRunnable = TokenRunnable() @@ -52,18 +53,18 @@ class Request { private val input = """{"mver":"1","subver":"1.2","host":"www.yangshipin.cn/#/tv/home?pid=","referer":"","canvas":"YSPANGLE(Apple,ANGLEMetalRenderer:AppleM1Pro,UnspecifiedVersion)"}""".toByteArray() - init { - handler.post(tokenRunnable) + private var listener: RequestListener? = null + + fun onCreate() { + Log.i(TAG, "onCreate") + fetchInfoV2() } fun onDestroy() { + Log.i(TAG, "onDestroy") handler.removeCallbacks(tokenRunnable) } - fun initYSP(context: Context) { - ysp = YSP(context) - } - var call: Call? = null private var callAuth: Call? = null @@ -72,9 +73,9 @@ class Request { val title = tvModel.title.value - val data = ysp?.getAuthData(tvModel) - val request = data?.let { AuthRequest(it) } - callAuth = request?.let { yspApiService.getAuth("guid=${ysp?.getGuid()}; $cookie", it) } + val data = YSP.getAuthData(tvModel) + val request = AuthRequest(data) + callAuth = request.let { yspApiService.getAuth("guid=${YSP.getGuid()}; $cookie", it) } callAuth?.enqueue(object : Callback { override fun onResponse(call: Call, response: Response) { @@ -83,7 +84,7 @@ class Request { if (liveInfo?.data?.token != null) { Log.i(TAG, "token ${liveInfo.data.token}") - ysp?.token = liveInfo.data.token + YSP.token = liveInfo.data.token fetchVideo(tvModel, cookie) } else { Log.e(TAG, "$title token error") @@ -153,12 +154,12 @@ class Request { val title = tvModel.title.value tvModel.seq = 0 - val data = ysp?.switch(tvModel) - val request = data?.let { LiveInfoRequest(it) } - call = request?.let { + val data = YSP.switch(tvModel) + val request = LiveInfoRequest(data) + call = request.let { yspApiService.getLiveInfo( - "guid=${ysp?.getGuid()}; $cookie", - ysp!!.token, + "guid=${YSP.getGuid()}; $cookie", + YSP.token, it ) } @@ -329,6 +330,7 @@ class Request { } fun fetchVideo(tvModel: TVViewModel) { + Log.d(TAG, "fetchVideo") if (token == "") { yspTokenService.getInfo("") .enqueue(object : Callback { @@ -383,7 +385,12 @@ class Request { val title = tvModel.title.value - fAuth = fAuthService.getAuth(tvModel.getTV().pid, "HD") + var qa = "HD" + if (tokenFH != "") { + qa = "FHD" + } + + fAuth = fAuthService.getAuth(tokenFH, tvModel.getTV().pid, qa) fAuth?.enqueue(object : Callback { override fun onResponse(call: Call, response: Response) { if (response.isSuccessful && response.body()?.data?.live_url != null) { @@ -412,6 +419,7 @@ class Request { } fun fetchData(tvModel: TVViewModel) { + Log.d(TAG, "fetchData") if (tvModel.getTV().channel == "港澳台") { fetchFAuth(tvModel) return @@ -434,12 +442,72 @@ class Request { } } - inner class TokenRunnable : Runnable { + class TokenRunnable : Runnable { override fun run() { fetchToken() } } + private fun fetchInfoV2() { + yspTokenService.getInfoV2() + .enqueue(object : Callback { + override fun onResponse(call: Call, response: Response) { + if (response.isSuccessful) { + val t = response.body()?.t + val f = response.body()?.f + val e = response.body()?.e + val c = response.body()?.c + if (!t.isNullOrEmpty()) { + token = t + Log.i(TAG, "token success $token") + if (e != null) { + handler.postDelayed( + tokenRunnable, + max(600000, (e - 1500) * 1000).toLong() + ) + } else { + Log.e(TAG, "e empty") + handler.postDelayed( + tokenRunnable, + 600000 + ) + } + } else { + Log.e(TAG, "token empty") + handler.postDelayed( + tokenRunnable, + 600000 + ) + } + if (!f.isNullOrEmpty()) { + tokenFH = f + Log.i(TAG, "tokenFH success $tokenFH") + } + if (c != null) { + Utils.setBetween(c * 1000L) + Log.i(TAG, "current time $c") + } + } else { + Log.e(TAG, "token status error") + handler.postDelayed( + tokenRunnable, + 600000 + ) + } + listener?.onRequestFinished() + } + + override fun onFailure(call: Call, t: Throwable) { + Log.e(TAG, "token request error $t") + handler.postDelayed( + tokenRunnable, + 600000 + ) + listener?.onRequestFinished() + } + }) + } + fun fetchToken() { yspTokenService.getToken(token) .enqueue(object : Callback { @@ -488,7 +556,7 @@ class Request { }) } - inner class BtraceRunnable(private val tvModel: TVViewModel) : Runnable { + class BtraceRunnable(private val tvModel: TVViewModel) : Runnable { override fun run() { fetchBtrace(tvModel) handler.postDelayed(this, 60000) @@ -498,11 +566,11 @@ class Request { fun fetchBtrace(tvModel: TVViewModel) { val title = tvModel.title.value - val guid = ysp?.getGuid()!! + val guid = YSP.getGuid() val pid = tvModel.pid.value!! val sid = tvModel.sid.value!! yspBtraceService.kvcollect( - c_timestamp = ysp?.generateGuid()!!, + c_timestamp = YSP.generateGuid(), guid = guid, c_guid = guid, prog = sid, @@ -510,7 +578,7 @@ class Request { fpid = pid, livepid = pid, sUrl = "https://www.yangshipin.cn/#/tv/home?pid=$pid", - playno = ysp?.getRand()!!, + playno = YSP.getRand(), ftime = getDateFormat("yyyy-MM-dd HH:mm:ss"), seq = tvModel.seq.toString(), ) @@ -602,7 +670,11 @@ class Request { } } - companion object { - private const val TAG = "Request" + interface RequestListener { + fun onRequestFinished() + } + + fun setRequestListener(listener: RequestListener) { + this.listener = listener } } \ No newline at end of file diff --git a/app/src/main/java/com/lizongying/mytv/Utils.kt b/app/src/main/java/com/lizongying/mytv/Utils.kt index 657d77c..2bef59f 100644 --- a/app/src/main/java/com/lizongying/mytv/Utils.kt +++ b/app/src/main/java/com/lizongying/mytv/Utils.kt @@ -26,6 +26,10 @@ object Utils { return (System.currentTimeMillis() - between) / 1000 } + fun setBetween(currentTimeMillis: Long) { + between = System.currentTimeMillis() - currentTimeMillis + } + suspend fun init() { var currentTimeMillis: Long = 0 try { diff --git a/app/src/main/java/com/lizongying/mytv/api/FAuthService.kt b/app/src/main/java/com/lizongying/mytv/api/FAuthService.kt index 1e597dd..870f807 100644 --- a/app/src/main/java/com/lizongying/mytv/api/FAuthService.kt +++ b/app/src/main/java/com/lizongying/mytv/api/FAuthService.kt @@ -2,11 +2,13 @@ package com.lizongying.mytv.api import retrofit2.Call import retrofit2.http.GET +import retrofit2.http.Header import retrofit2.http.Query interface FAuthService { @GET("api/v3/hub/live/auth-url") fun getAuth( + @Header("token") token: String, @Query("live_id") live_id: String = "", @Query("live_qa") live_qa: String = "", ): Call diff --git a/app/src/main/java/com/lizongying/mytv/api/Info.kt b/app/src/main/java/com/lizongying/mytv/api/Info.kt index 3bc7ae0..0bec143 100644 --- a/app/src/main/java/com/lizongying/mytv/api/Info.kt +++ b/app/src/main/java/com/lizongying/mytv/api/Info.kt @@ -15,6 +15,13 @@ data class Token( val t: String?, ) +data class InfoV2( + val f: String?, + val t: String?, + val e: Int?, + val c: Int?, +) + data class Release( val code: Int?, val msg: String?, 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 de104f5..5a20ae6 100644 --- a/app/src/main/java/com/lizongying/mytv/api/YSP.kt +++ b/app/src/main/java/com/lizongying/mytv/api/YSP.kt @@ -9,7 +9,9 @@ import com.lizongying.mytv.models.TVViewModel import kotlin.math.floor import kotlin.random.Random -class YSP(var context: Context) { +object YSP { + private const val TAG = "YSP" + private var cnlid = "" private var livepid = "" @@ -53,14 +55,10 @@ class YSP(var context: Context) { private var appid = "ysp_pc" var token = "" - private var encryptor: Encryptor? = null - - init { - if (context is MainActivity) { - encryptor = Encryptor() - encryptor!!.init(context) - } + private var encryptor = Encryptor() + fun init(context: Context) { + encryptor.init(context) guid = getGuid() } @@ -78,7 +76,7 @@ class YSP(var context: Context) { timeStr = getTimeStr() cKey = - encryptor!!.encrypt(cnlid, timeStr, appVer, guid, platform) + encryptor.encrypt(cnlid, timeStr, appVer, guid, platform) signature = getSignature() return """{"cnlid":"$cnlid","livepid":"$livepid","stream":"$stream","guid":"$guid","cKey":"$cKey","adjust":$adjust,"sphttps":"$sphttps","platform":"$platform","cmd":"$cmd","encryptVer":"$encryptVer","dtype":"$dtype","devid":"$devid","otype":"$otype","appVer":"$appVer","app_version":"$appVersion","rand_str":"$randStr","channel":"$channel","defn":"$defn","signature":"$signature"}""" } @@ -134,18 +132,14 @@ class YSP(var context: Context) { private fun getSignature(): String { val e = "adjust=${adjust}&appVer=${appVer}&app_version=$appVersion&cKey=$cKey&channel=$channel&cmd=$cmd&cnlid=$cnlid&defn=${defn}&devid=${devid}&dtype=${dtype}&encryptVer=${encryptVer}&guid=${guid}&livepid=${livepid}&otype=${otype}&platform=${platform}&rand_str=${randStr}&sphttps=${sphttps}&stream=${stream}".toByteArray() - val hashedData = encryptor?.hash(e) ?: return "" + val hashedData = encryptor.hash(e) ?: return "" return hashedData.let { it -> it.joinToString("") { "%02x".format(it) } } } private fun getAuthSignature(): String { val e = "appid=${appid}&guid=${guid}&pid=${livepid}&rand_str=${randStr}".toByteArray() - val hashedData = encryptor?.hash2(e) ?: return "" + val hashedData = encryptor.hash2(e) ?: return "" return hashedData.let { it -> it.joinToString("") { "%02x".format(it) } } } - - companion object { - private const val TAG = "YSP" - } } \ No newline at end of file diff --git a/app/src/main/java/com/lizongying/mytv/api/YSPTokenService.kt b/app/src/main/java/com/lizongying/mytv/api/YSPTokenService.kt index 80b402a..40bd969 100644 --- a/app/src/main/java/com/lizongying/mytv/api/YSPTokenService.kt +++ b/app/src/main/java/com/lizongying/mytv/api/YSPTokenService.kt @@ -15,4 +15,8 @@ interface YSPTokenService { fun getToken( @Query("token") token: String = "", ): Call + + @GET("my-tv/v2/info") + fun getInfoV2( + ): Call } \ No newline at end of file