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",