diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml index 4973964..ca10c36 100644 --- a/.github/ISSUE_TEMPLATE/bug.yml +++ b/.github/ISSUE_TEMPLATE/bug.yml @@ -19,8 +19,8 @@ body: label: my-ty 版本 description: 请选择正在使用的版本 options: - - 最新稳定版 - - 最新 CI 版 + - 通用版 + - 专用版 validations: required: true - type: textarea diff --git a/README.md b/README.md index 6e9abd4..b8477f4 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,20 @@ ## 更新日志 +### v1.6.4(通用) + +* 增加CETV1 +* 增加凤凰卫视 +* 默认关闭开机启动 + +### v1.6.3(安卓5及以上专用) + +* 增加CETV1 +* 凤凰卫视增强画质 +* 默认关闭开机启动 +* 延迟菜单自动关闭时间 +* 解决一些可能导致首次打开时黑屏的问题 + ### v1.6.2(通用) * 修复按键无效的问题 @@ -199,17 +213,15 @@ adb install my-tv.apk ## TODO * 音量不同 -* 大湾区卫视、广东4k超高清、广东珠江 -* CETV教育频道 +* 大湾区卫视、广东4k超高清、广东珠江、三沙卫视 * CHC高清三个电影频道 * 地方频道 * 收藏夹 * 自定义源 -* 凤凰卫视、凤凰资讯台 * 海外 -* 1.5.0 无法安装,1.5.1 可以安装 * 节目增加预告 * 频道列表优化 +* 自动更新 ## 赞赏 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 512a4a7..3bb6bc5 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -41,7 +41,6 @@ + android:exported="false"/> \ No newline at end of file diff --git a/app/src/main/java/com/lizongying/mytv/CardPresenter.kt b/app/src/main/java/com/lizongying/mytv/CardPresenter.kt index cd6dbf4..d2455f8 100644 --- a/app/src/main/java/com/lizongying/mytv/CardPresenter.kt +++ b/app/src/main/java/com/lizongying/mytv/CardPresenter.kt @@ -31,32 +31,10 @@ class CardPresenter( cardView.setMainImageDimensions(CARD_WIDTH, CARD_HEIGHT) cardView.tag = tvViewModel.videoUrl.value - when (tvViewModel.title.value) { - "CCTV8K 超高清" -> Glide.with(viewHolder.view.context) - .load(R.drawable.cctv8k) - .centerInside() - .into(cardView.mainImageView) - - "天津卫视" -> Glide.with(viewHolder.view.context) - .load(R.drawable.tianjin) - .centerInside() - .into(cardView.mainImageView) - - "新疆卫视" -> Glide.with(viewHolder.view.context) - .load(R.drawable.xinjiang) - .centerInside() - .into(cardView.mainImageView) - - "兵团卫视" -> Glide.with(viewHolder.view.context) - .load(R.drawable.bingtuan) - .centerInside() - .into(cardView.mainImageView) - - else -> Glide.with(viewHolder.view.context) - .load(tvViewModel.logo.value) - .centerInside() - .into(cardView.mainImageView) - } + Glide.with(viewHolder.view.context) + .load(tvViewModel.logo.value) + .centerInside() + .into(cardView.mainImageView) cardView.setBackgroundColor(Color.WHITE) cardView.setMainImageScaleType(ImageView.ScaleType.CENTER_INSIDE) diff --git a/app/src/main/java/com/lizongying/mytv/InfoFragment.kt b/app/src/main/java/com/lizongying/mytv/InfoFragment.kt index 258a9af..744a674 100644 --- a/app/src/main/java/com/lizongying/mytv/InfoFragment.kt +++ b/app/src/main/java/com/lizongying/mytv/InfoFragment.kt @@ -30,27 +30,9 @@ class InfoFragment : Fragment() { fun show(tvViewModel: TVViewModel) { binding.textView.text = tvViewModel.title.value - when (tvViewModel.title.value) { - "CCTV8K 超高清" -> Glide.with(this) - .load(R.drawable.cctv8k) - .into(binding.infoLogo) - - "天津卫视" -> Glide.with(this) - .load(R.drawable.tianjin) - .into(binding.infoLogo) - - "新疆卫视" -> Glide.with(this) - .load(R.drawable.xinjiang) - .into(binding.infoLogo) - - "兵团卫视" -> Glide.with(this) - .load(R.drawable.bingtuan) - .into(binding.infoLogo) - - else -> Glide.with(this) - .load(tvViewModel.logo.value) - .into(binding.infoLogo) - } + Glide.with(this) + .load(tvViewModel.logo.value) + .into(binding.infoLogo) val program = tvViewModel.getProgramOne() if (program != null) { diff --git a/app/src/main/java/com/lizongying/mytv/MainActivity.kt b/app/src/main/java/com/lizongying/mytv/MainActivity.kt index 9b5a276..4857c23 100644 --- a/app/src/main/java/com/lizongying/mytv/MainActivity.kt +++ b/app/src/main/java/com/lizongying/mytv/MainActivity.kt @@ -19,7 +19,7 @@ import kotlinx.coroutines.async import kotlinx.coroutines.launch -class MainActivity : FragmentActivity() { +class MainActivity : FragmentActivity(), Request.RequestListener { private var ready = 0 private val playerFragment = PlayerFragment() @@ -33,24 +33,27 @@ class MainActivity : FragmentActivity() { private lateinit var gestureDetector: GestureDetector private val handler = Handler() - private val delayHideMain: Long = 5000 + 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 @@ -157,7 +160,7 @@ class MainActivity : FragmentActivity() { fun fragmentReady() { ready++ Log.i(TAG, "ready $ready") - if (ready == 4) { + if (ready == 5) { mainFragment.fragmentReady() } } @@ -444,7 +447,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 ecc2aed..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,8 +11,10 @@ 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 import com.lizongying.mytv.api.YSP import com.lizongying.mytv.api.YSPApiService import com.lizongying.mytv.api.YSPBtraceService @@ -28,20 +29,22 @@ import retrofit2.Response import javax.crypto.Cipher import javax.crypto.spec.IvParameterSpec 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() @@ -50,12 +53,16 @@ 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 initYSP(context: Context) { - ysp = YSP(context) + fun onDestroy() { + Log.i(TAG, "onDestroy") + handler.removeCallbacks(tokenRunnable) } var call: Call? = null @@ -66,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) { @@ -77,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") @@ -147,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 ) } @@ -323,6 +330,7 @@ class Request { } fun fetchVideo(tvModel: TVViewModel) { + Log.d(TAG, "fetchVideo") if (token == "") { yspTokenService.getInfo("") .enqueue(object : Callback { @@ -377,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) { @@ -406,6 +419,7 @@ class Request { } fun fetchData(tvModel: TVViewModel) { + Log.d(TAG, "fetchData") if (tvModel.getTV().channel == "港澳台") { fetchFAuth(tvModel) return @@ -428,32 +442,121 @@ class Request { } } - inner class TokenRunnable : Runnable { + class TokenRunnable : Runnable { override fun run() { fetchToken() - handler.postDelayed(this, 600000) } } + 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.getInfo(token) - .enqueue(object : Callback { - override fun onResponse(call: Call, response: Response) { + yspTokenService.getToken(token) + .enqueue(object : Callback { + override fun onResponse(call: Call, response: Response) { if (response.isSuccessful) { - token = response.body()?.data?.token!! - Log.i(TAG, "info success $token") + val t = response.body()?.t + val e = response.body()?.e + if (!t.isNullOrEmpty()) { + token = t + Log.e(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 + ) + } } else { Log.e(TAG, "token status error") + handler.postDelayed( + tokenRunnable, + 600000 + ) } } - override fun onFailure(call: Call, t: Throwable) { + override fun onFailure(call: Call, t: Throwable) { Log.e(TAG, "token request error $t") + handler.postDelayed( + tokenRunnable, + 600000 + ) } }) } - inner class BtraceRunnable(private val tvModel: TVViewModel) : Runnable { + class BtraceRunnable(private val tvModel: TVViewModel) : Runnable { override fun run() { fetchBtrace(tvModel) handler.postDelayed(this, 60000) @@ -463,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, @@ -475,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(), ) @@ -567,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/SP.kt b/app/src/main/java/com/lizongying/mytv/SP.kt index 08da1d6..583bd5f 100644 --- a/app/src/main/java/com/lizongying/mytv/SP.kt +++ b/app/src/main/java/com/lizongying/mytv/SP.kt @@ -35,8 +35,7 @@ object SP { set(value) = sp.edit().putBoolean(KEY_CHANNEL_NUM, value).apply() var bootStartup: Boolean - // TODO It‘s more friendly to change the default value to false - get() = sp.getBoolean(KEY_BOOT_STARTUP, true) + get() = sp.getBoolean(KEY_BOOT_STARTUP, false) set(value) = sp.edit().putBoolean(KEY_BOOT_STARTUP, value).apply() var itemPosition: Int diff --git a/app/src/main/java/com/lizongying/mytv/TV.kt b/app/src/main/java/com/lizongying/mytv/TV.kt index 22e58c7..ee8b1ff 100644 --- a/app/src/main/java/com/lizongying/mytv/TV.kt +++ b/app/src/main/java/com/lizongying/mytv/TV.kt @@ -9,7 +9,7 @@ data class TV( var videoUrl: List, var videoIndex: Int = 0, var channel: String = "", - var logo: String = "", + var logo: Any = "", var pid: String = "", var sid: String = "", var programId: String = "", diff --git a/app/src/main/java/com/lizongying/mytv/TVList.kt b/app/src/main/java/com/lizongying/mytv/TVList.kt index 966ee72..d30d074 100644 --- a/app/src/main/java/com/lizongying/mytv/TVList.kt +++ b/app/src/main/java/com/lizongying/mytv/TVList.kt @@ -127,7 +127,7 @@ object TVList { ), TV( 8, - "CCTV9 记录", + "CCTV9 纪录", "CCTV9", listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226197/index.m3u8"), 0, @@ -292,7 +292,7 @@ object TVList { listOf(), 0, "央视", - "", + R.drawable.cctv8k, "600156816", "2020603421", "", @@ -838,7 +838,7 @@ object TVList { listOf(), 0, "地方", - "", + R.drawable.tianjin, "600152137", "2019927003", "", @@ -852,7 +852,7 @@ object TVList { listOf(), 0, "地方", - "", + R.drawable.xinjiang, "600152138", "2019927403", "", @@ -866,17 +866,31 @@ object TVList { listOf(), 0, "地方", - "", + R.drawable.bingtuan, "600170344", "2022606701", "", true, mustToken = false ), + TV( + 57, + "CETV1", + "CETV1", + listOf(), + 0, + "地方", + R.drawable.cetv1, + "600171827", + "2022823801", + "", + true, + mustToken = false + ), ), "港澳台" to listOf( TV( - 57, + 58, "凤凰卫视资讯台", "", listOf(), @@ -890,7 +904,7 @@ object TVList { mustToken = false ), TV( - 58, + 59, "凤凰卫视中文台", "", listOf(), @@ -904,7 +918,7 @@ object TVList { mustToken = false ), TV( - 59, + 60, "凤凰卫视香港台", "", listOf(), @@ -920,7 +934,7 @@ object TVList { ), "国际" to listOf( TV( - 60, + 61, "CGTN", "CGTN", listOf("http://live.cgtn.com/1000/prog_index.m3u8"), @@ -934,7 +948,7 @@ object TVList { mustToken = false ), TV( - 61, + 62, "CGTN 法语频道", "CGTN法语频道", listOf("https://livefr.cgtn.com/1000f/prog_index.m3u8"), @@ -948,7 +962,7 @@ object TVList { mustToken = false ), TV( - 62, + 63, "CGTN 俄语频道", "CGTN俄语频道", listOf("http://liveru.cgtn.com/1000r/prog_index.m3u8"), @@ -962,7 +976,7 @@ object TVList { mustToken = false ), TV( - 63, + 64, "CGTN 阿拉伯语频道", "CGTN阿拉伯语频道", listOf("http://livear.cgtn.com/1000a/prog_index.m3u8"), @@ -976,7 +990,7 @@ object TVList { mustToken = false ), TV( - 64, + 65, "CGTN 西班牙语频道", "CGTN西班牙语频道", listOf( @@ -993,7 +1007,7 @@ object TVList { mustToken = false ), TV( - 65, + 66, "CGTN 纪录频道", "CGTN外语纪录频道", listOf("https://livedoc.cgtn.com/500d/prog_index.m3u8"), 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 c1898bc..0bec143 100644 --- a/app/src/main/java/com/lizongying/mytv/api/Info.kt +++ b/app/src/main/java/com/lizongying/mytv/api/Info.kt @@ -1,6 +1,5 @@ package com.lizongying.mytv.api - data class Info( val code: Int?, val msg: String?, @@ -11,6 +10,18 @@ data class Info( ) } +data class Token( + val e: Int?, + 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 7d08cd1..40bd969 100644 --- a/app/src/main/java/com/lizongying/mytv/api/YSPTokenService.kt +++ b/app/src/main/java/com/lizongying/mytv/api/YSPTokenService.kt @@ -10,4 +10,13 @@ interface YSPTokenService { fun getInfo( @Query("token") token: String = "", ): Call + + @GET("my-tv/v2/token") + fun getToken( + @Query("token") token: String = "", + ): Call + + @GET("my-tv/v2/info") + fun getInfoV2( + ): Call } \ No newline at end of file diff --git a/app/src/main/java/com/lizongying/mytv/models/TVViewModel.kt b/app/src/main/java/com/lizongying/mytv/models/TVViewModel.kt index 74b2f96..20dd51d 100644 --- a/app/src/main/java/com/lizongying/mytv/models/TVViewModel.kt +++ b/app/src/main/java/com/lizongying/mytv/models/TVViewModel.kt @@ -53,8 +53,8 @@ class TVViewModel(private var tv: TV) : ViewModel() { val videoIndex: LiveData get() = _videoIndex - private val _logo = MutableLiveData() - val logo: LiveData + private val _logo = MutableLiveData() + val logo: LiveData get() = _logo private val _pid = MutableLiveData() @@ -73,11 +73,8 @@ class TVViewModel(private var tv: TV) : ViewModel() { val ready: LiveData get() = _ready - private var mMinimumLoadableRetryCount = 5 - var seq = 0 - fun addVideoUrl(url: String) { if (_videoUrl.value?.isNotEmpty() == true) { if (_videoUrl.value!!.last().contains("cctv.cn")) { @@ -114,10 +111,6 @@ class TVViewModel(private var tv: TV) : ViewModel() { _videoIndex.value = videoIndex } - fun setLogo(url: String) { - _logo.value = url - } - init { _id.value = tv.id _title.value = tv.title @@ -197,10 +190,6 @@ class TVViewModel(private var tv: TV) : ViewModel() { mHeaders = headers } - fun setMinimumLoadableRetryCount(minimumLoadableRetryCount: Int) { - mMinimumLoadableRetryCount = minimumLoadableRetryCount - } - /** * (playerView?.player as ExoPlayer).setMediaSource(tvViewModel.buildSource()) */ diff --git a/app/src/main/res/drawable/cetv1.png b/app/src/main/res/drawable/cetv1.png new file mode 100644 index 0000000..9309b17 Binary files /dev/null and b/app/src/main/res/drawable/cetv1.png differ diff --git a/app/src/main/res/raw/channels.json b/app/src/main/res/raw/channels.json index 9bc48af..7b9f469 100644 --- a/app/src/main/res/raw/channels.json +++ b/app/src/main/res/raw/channels.json @@ -130,7 +130,7 @@ "programId": "600004078", "needToken": true, "mustToken": false, - "title": "CCTV9 记录", + "title": "CCTV9 纪录", "videoUrl": [ "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226197/index.m3u8" ] @@ -863,7 +863,7 @@ { "id": 56, "videoIndex": 0, - "channel": "国际频道", + "channel": "国际", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/a72dff758ca1c17cd0ecc8cedc11b893d208f409d5e6302faa0e9d298848abc3.png?imageMogr2/format/webp", "pid": "600014550", "sid": "2001656803", @@ -878,7 +878,7 @@ { "id": 57, "videoIndex": 0, - "channel": "国际频道", + "channel": "国际", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/a8d0046a47433d952bf6ed17062deb8bd2184ba9aec0f7781df6bf9487a3ffcf.png?imageMogr2/format/webp", "pid": "600084704", "sid": "2010153503", @@ -893,7 +893,7 @@ { "id": 58, "videoIndex": 0, - "channel": "国际频道", + "channel": "国际", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/bf0a820893cbaf20dd0333e27042e1ef9c8806e5b602b6a8c95af399db0bc77a.png?imageMogr2/format/webp", "pid": "600084758", "sid": "2010152603", @@ -908,7 +908,7 @@ { "id": 59, "videoIndex": 0, - "channel": "国际频道", + "channel": "国际", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/2e44e2aa3e7a1cedf07fd0ae59fe69e86a60a2632660a006e3e9e7397b2d107e.png?imageMogr2/format/webp", "pid": "600084782", "sid": "2010155203", @@ -923,7 +923,7 @@ { "id": 60, "videoIndex": 0, - "channel": "国际频道", + "channel": "国际", "logo": "https://resources.yangshipin.cn/assets/oms/image/202309/7c337e3dbe64402ec7e4678a619a4a6d95144e42f35161181ff78e143b7cf67a.png?imageMogr2/format/webp", "pid": "600084744", "sid": "2010152503", @@ -939,7 +939,7 @@ { "id": 61, "videoIndex": 0, - "channel": "国际频道", + "channel": "国际", "logo": "https://resources.yangshipin.cn/assets/oms/image/202309/74d3ac436a7e374879578de1d87a941fbf566d39d5632b027c5097891ed32bd5.png?imageMogr2/format/webp", "pid": "600084781", "sid": "2010155403",