Compare commits

..
1 Commits
Author SHA1 Message Date
Li ZongYing 5aa08f51a1 error page 2024-04-26 19:57:12 +08:00
26 changed files with 339 additions and 107 deletions
+6
View File
@@ -1,5 +1,11 @@
## 更新日志 ## 更新日志
### v1.8.6(通用)
* 增加错误显示
* 节目预告优化
* 频道列表页单击切换频道
### v1.8.4(通用) ### v1.8.4(通用)
* 解決部分情況下打開後黑屏问题 * 解決部分情況下打開後黑屏问题
+12 -16
View File
@@ -4,17 +4,16 @@
## 使用 ## 使用
下载安装: 1. 下载
[github](https://github.com/lizongying/my-tv/releases/) * [github](https://github.com/lizongying/my-tv/releases/)
[gitee](https://gitee.com/lizongying/my-tv/releases/) * [gitee](https://gitee.com/lizongying/my-tv/releases/)
2. 安裝
小米电视可以使用小米电视助手进行安装 * U盘安装
* 小米电视可以使用小米电视助手进行安装
如电视可以启用ADB,也可以通过ADB进行安装: * 如电视可以启用ADB,也可以通过ADB进行安装
```shell
```shell adb install my-tv.apk
adb install my-tv.apk ```
```
![image](./screenshots/img_3.png) ![image](./screenshots/img_3.png)
![image](./screenshots/img_2.png) ![image](./screenshots/img_2.png)
@@ -32,14 +31,11 @@ adb install my-tv.apk
* 地方频道 * 地方频道
* 收藏夹 * 收藏夹
* 海外 * 海外
* 1.5.0 无法安装,1.5.1 可以安装
* 节目增加预告
* epg更新后菜单更新
* 隐藏频道 * 隐藏频道
* 亮度调节 * 亮度调节
* 音量调节 * 音量调节
* 错误页 * 軟解
* 频道列表页只点击一次即可 * 自動更新
## 版权说明 ## 版权说明
Binary file not shown.
Binary file not shown.
@@ -1,8 +1,11 @@
package com.lizongying.mytv package com.lizongying.mytv
import android.util.Log
import android.view.KeyEvent import android.view.KeyEvent
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View import android.view.View
import android.view.ViewConfiguration
import android.view.ViewGroup import android.view.ViewGroup
import android.view.animation.ScaleAnimation import android.view.animation.ScaleAnimation
import androidx.core.view.marginTop import androidx.core.view.marginTop
@@ -12,6 +15,7 @@ import com.bumptech.glide.Glide
import com.lizongying.mytv.databinding.CardBinding import com.lizongying.mytv.databinding.CardBinding
import com.lizongying.mytv.models.TVListViewModel import com.lizongying.mytv.models.TVListViewModel
import com.lizongying.mytv.models.TVViewModel import com.lizongying.mytv.models.TVViewModel
import kotlin.math.abs
class CardAdapter( class CardAdapter(
@@ -45,6 +49,7 @@ class CardAdapter(
binding.desc.layoutParams = layoutParams binding.desc.layoutParams = layoutParams
val cardView = binding.root val cardView = binding.root
cardView.isClickable = true
cardView.isFocusable = true cardView.isFocusable = true
cardView.isFocusableInTouchMode = true cardView.isFocusableInTouchMode = true
return ViewHolder(cardView, binding) return ViewHolder(cardView, binding)
@@ -55,14 +60,14 @@ class CardAdapter(
recyclerView.invalidate() recyclerView.invalidate()
} }
private fun startScaleAnimation(view: View, fromScale: Float, toScale: Float, duration: Long) { private fun startScaleAnimation(view: View) {
val scaleAnimation = ScaleAnimation( val scaleAnimation = ScaleAnimation(
fromScale, toScale, 0.9f, 1.0f,
fromScale, toScale, 0.9f, 1.0f,
ScaleAnimation.RELATIVE_TO_SELF, 0.5f, ScaleAnimation.RELATIVE_TO_SELF, 0.5f,
ScaleAnimation.RELATIVE_TO_SELF, 0.5f ScaleAnimation.RELATIVE_TO_SELF, 0.5f
) )
scaleAnimation.duration = duration scaleAnimation.duration = 200
scaleAnimation.fillAfter = false scaleAnimation.fillAfter = false
view.startAnimation(scaleAnimation) view.startAnimation(scaleAnimation)
} }
@@ -80,7 +85,7 @@ class CardAdapter(
focused = cardView focused = cardView
if (focusable) { if (focusable) {
startScaleAnimation(cardView, 0.9f, 1.0f, 200) startScaleAnimation(cardView)
viewHolder.focus(true) viewHolder.focus(true)
} }
} else { } else {
@@ -94,6 +99,34 @@ class CardAdapter(
listener?.onItemClicked(item) listener?.onItemClicked(item)
} }
var downX = 0f
var downY = 0f
val touchSlop = ViewConfiguration.get(cardView.context).scaledTouchSlop
cardView.setOnTouchListener { _, event ->
when (event.action) {
MotionEvent.ACTION_DOWN -> {
downX = event.x
downY = event.y
true
}
MotionEvent.ACTION_UP -> {
val upX = event.x
val upY = event.y
val deltaX = abs(upX - downX)
val deltaY = abs(upY - downY)
if (deltaX < touchSlop && deltaY < touchSlop) {
// 如果位移量小于阈值,则执行点击操作
cardView.performClick()
}
true
}
else -> false
}
}
cardView.setOnKeyListener { _, keyCode, event: KeyEvent? -> cardView.setOnKeyListener { _, keyCode, event: KeyEvent? ->
if (event?.action == KeyEvent.ACTION_DOWN) { if (event?.action == KeyEvent.ACTION_DOWN) {
return@setOnKeyListener listener?.onKey(keyCode) ?: false return@setOnKeyListener listener?.onKey(keyCode) ?: false
@@ -132,6 +165,33 @@ class CardAdapter(
} }
} }
fun updateEPG() {
for (i in 0 until recyclerView.childCount) {
val childView = recyclerView.getChildAt(i)
val viewHolder = recyclerView.getChildViewHolder(childView) as ViewHolder
if (viewHolder.view.tag != null && viewHolder.view.tag is TVViewModel) {
val tvViewModel = viewHolder.view.tag as TVViewModel
val epg = tvViewModel.epg.value?.filter { it.beginTime < Utils.getDateTimestamp() }
if (!epg.isNullOrEmpty()) {
val title = epg.last().title
if (viewHolder.binding.desc.text != title) {
viewHolder.binding.desc.text = title
Log.i(TAG, "updateEPG $title")
}
} else {
if (viewHolder.binding.desc.text != "") {
viewHolder.binding.desc.text = ""
Log.i(TAG, "updateEPG")
}
}
}
}
}
fun toPosition(position: Int) { fun toPosition(position: Int) {
recyclerView.post { recyclerView.post {
recyclerView.scrollToPosition(position) recyclerView.scrollToPosition(position)
@@ -0,0 +1,53 @@
package com.lizongying.mytv
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.view.marginLeft
import androidx.core.view.marginTop
import androidx.fragment.app.Fragment
import com.lizongying.mytv.databinding.ErrorBinding
class ErrorFragment : Fragment() {
private var _binding: ErrorBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = ErrorBinding.inflate(inflater, container, false)
val application = requireActivity().applicationContext as MyTvApplication
binding.logo.layoutParams.width = application.px2Px(binding.logo.layoutParams.width)
binding.logo.layoutParams.height = application.px2Px(binding.logo.layoutParams.height)
val layoutParamsMain = binding.main.layoutParams as ViewGroup.MarginLayoutParams
layoutParamsMain.leftMargin = application.px2Px(binding.main.marginLeft)
binding.main.layoutParams = layoutParamsMain
val layoutParams = binding.msg.layoutParams as ViewGroup.MarginLayoutParams
layoutParams.topMargin = application.px2Px(binding.msg.marginTop)
binding.msg.layoutParams = layoutParams
binding.msg.textSize = application.px2PxFont(binding.msg.textSize)
(activity as MainActivity).fragmentReady(TAG)
return binding.root
}
fun show(msg: String) {
binding.msg.text = msg
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
companion object {
private const val TAG = "ErrorFragment"
}
}
@@ -52,6 +52,7 @@ class InfoFragment : Fragment() {
binding.logo.setPadding(application.px2Px(binding.logo.paddingTop)) binding.logo.setPadding(application.px2Px(binding.logo.paddingTop))
binding.main.layoutParams.width = application.px2Px(binding.main.layoutParams.width) binding.main.layoutParams.width = application.px2Px(binding.main.layoutParams.width)
binding.main.setPadding(application.px2Px(binding.main.paddingTop)) binding.main.setPadding(application.px2Px(binding.main.paddingTop))
val layoutParamsMain = binding.main.layoutParams as ViewGroup.MarginLayoutParams val layoutParamsMain = binding.main.layoutParams as ViewGroup.MarginLayoutParams
layoutParamsMain.leftMargin = application.px2Px(binding.main.marginLeft) layoutParamsMain.leftMargin = application.px2Px(binding.main.marginLeft)
binding.main.layoutParams = layoutParamsMain binding.main.layoutParams = layoutParamsMain
@@ -59,6 +60,7 @@ class InfoFragment : Fragment() {
val layoutParamsDesc = binding.desc.layoutParams as ViewGroup.MarginLayoutParams val layoutParamsDesc = binding.desc.layoutParams as ViewGroup.MarginLayoutParams
layoutParamsDesc.topMargin = application.px2Px(binding.desc.marginTop) layoutParamsDesc.topMargin = application.px2Px(binding.desc.marginTop)
binding.desc.layoutParams = layoutParamsDesc binding.desc.layoutParams = layoutParamsDesc
binding.title.textSize = application.px2PxFont(binding.title.textSize) binding.title.textSize = application.px2PxFont(binding.title.textSize)
binding.desc.textSize = application.px2PxFont(binding.desc.textSize) binding.desc.textSize = application.px2PxFont(binding.desc.textSize)
@@ -17,6 +17,7 @@ import android.widget.Toast
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import com.lizongying.mytv.models.TVViewModel import com.lizongying.mytv.models.TVViewModel
import com.lizongying.mytv.requests.Request
import kotlinx.coroutines.CoroutineStart import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async import kotlinx.coroutines.async
@@ -27,6 +28,7 @@ class MainActivity : FragmentActivity(), Request.RequestListener {
private var ready = 0 private var ready = 0
private val playerFragment = PlayerFragment() private val playerFragment = PlayerFragment()
private val errorFragment = ErrorFragment()
private val mainFragment = MainFragment() private val mainFragment = MainFragment()
private val infoFragment = InfoFragment() private val infoFragment = InfoFragment()
private val channelFragment = ChannelFragment() private val channelFragment = ChannelFragment()
@@ -53,7 +55,6 @@ class MainActivity : FragmentActivity(), Request.RequestListener {
} }
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
Log.i(TAG, "onCreate")
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main) setContentView(R.layout.activity_main)
@@ -67,11 +68,13 @@ class MainActivity : FragmentActivity(), Request.RequestListener {
if (savedInstanceState == null) { if (savedInstanceState == null) {
supportFragmentManager.beginTransaction() supportFragmentManager.beginTransaction()
.add(R.id.main_browse_fragment, playerFragment) .add(R.id.main_browse_fragment, playerFragment)
.add(R.id.main_browse_fragment, errorFragment)
.add(R.id.main_browse_fragment, timeFragment) .add(R.id.main_browse_fragment, timeFragment)
.add(R.id.main_browse_fragment, infoFragment) .add(R.id.main_browse_fragment, infoFragment)
.add(R.id.main_browse_fragment, channelFragment) .add(R.id.main_browse_fragment, channelFragment)
.add(R.id.main_browse_fragment, mainFragment) .add(R.id.main_browse_fragment, mainFragment)
.hide(mainFragment) .hide(mainFragment)
.hide(errorFragment)
.commit() .commit()
} }
gestureDetector = GestureDetector(this, GestureListener()) gestureDetector = GestureDetector(this, GestureListener())
@@ -103,6 +106,44 @@ class MainActivity : FragmentActivity(), Request.RequestListener {
} }
} }
fun showErrorFragment(msg: String) {
errorFragment.show(msg)
if (errorFragment.isVisible) {
return
}
supportFragmentManager.beginTransaction()
.show(errorFragment)
.commit()
}
fun hideErrorFragment() {
errorFragment.show("")
if (!errorFragment.isVisible) {
return
}
supportFragmentManager.beginTransaction()
.hide(errorFragment)
.commit()
}
fun showPlayerFragment() {
if (playerFragment.isVisible) {
return
}
supportFragmentManager.beginTransaction()
.show(playerFragment)
.commit()
}
fun hidePlayerFragment() {
if (!playerFragment.isVisible) {
return
}
supportFragmentManager.beginTransaction()
.hide(playerFragment)
.commit()
}
private fun showChannel(channel: String) { private fun showChannel(channel: String) {
if (!mainFragment.isHidden) { if (!mainFragment.isHidden) {
return return
@@ -183,7 +224,7 @@ class MainActivity : FragmentActivity(), Request.RequestListener {
fun fragmentReady(tag: String) { fun fragmentReady(tag: String) {
ready++ ready++
Log.i(TAG, "ready $tag $ready ") Log.i(TAG, "ready $tag $ready ")
if (ready == 7) { if (ready == 8) {
mainFragment.fragmentReady() mainFragment.fragmentReady()
showTime() showTime()
} }
@@ -20,8 +20,10 @@ import com.lizongying.mytv.api.YSP
import com.lizongying.mytv.databinding.MenuBinding import com.lizongying.mytv.databinding.MenuBinding
import com.lizongying.mytv.databinding.RowBinding import com.lizongying.mytv.databinding.RowBinding
import com.lizongying.mytv.models.ProgramType import com.lizongying.mytv.models.ProgramType
import com.lizongying.mytv.models.TVList
import com.lizongying.mytv.models.TVListViewModel import com.lizongying.mytv.models.TVListViewModel
import com.lizongying.mytv.models.TVViewModel import com.lizongying.mytv.models.TVViewModel
import com.lizongying.mytv.requests.Request
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@@ -183,8 +185,13 @@ class MainFragment : Fragment(), CardAdapter.ItemListener {
if (tvViewModel.errInfo.value != null if (tvViewModel.errInfo.value != null
&& tvViewModel.getTV().id == itemPosition && tvViewModel.getTV().id == itemPosition
) { ) {
Toast.makeText(context, tvViewModel.errInfo.value, Toast.LENGTH_SHORT) if (tvViewModel.errInfo.value == "") {
.show() (activity as? MainActivity)?.showPlayerFragment()
(activity as? MainActivity)?.hideErrorFragment()
} else {
(activity as? MainActivity)?.hidePlayerFragment()
(activity as? MainActivity)?.showErrorFragment(tvViewModel.errInfo.value.toString())
}
} }
} }
tvViewModel.ready.observe(viewLifecycleOwner) { _ -> tvViewModel.ready.observe(viewLifecycleOwner) { _ ->
@@ -266,8 +273,6 @@ class MainFragment : Fragment(), CardAdapter.ItemListener {
} }
override fun onItemHasFocus(tvViewModel: TVViewModel) { override fun onItemHasFocus(tvViewModel: TVViewModel) {
tvListViewModel.setItemPositionCurrent(tvViewModel.getTV().id)
val row = tvViewModel.getRowPosition() val row = tvViewModel.getRowPosition()
for (i in rowList) { for (i in rowList) {
@@ -283,7 +288,6 @@ class MainFragment : Fragment(), CardAdapter.ItemListener {
} }
override fun onItemClicked(tvViewModel: TVViewModel) { override fun onItemClicked(tvViewModel: TVViewModel) {
Log.i(TAG, "onItemClicked")
if (this.isHidden) { if (this.isHidden) {
(activity as? MainActivity)?.switchMainFragment() (activity as? MainActivity)?.switchMainFragment()
return return
@@ -293,6 +297,7 @@ class MainFragment : Fragment(), CardAdapter.ItemListener {
itemPosition = tvViewModel.getTV().id itemPosition = tvViewModel.getTV().id
tvListViewModel.setItemPosition(itemPosition) tvListViewModel.setItemPosition(itemPosition)
tvListViewModel.getTVViewModel(itemPosition)?.changed("menu") tvListViewModel.getTVViewModel(itemPosition)?.changed("menu")
Log.i(TAG, "onItemClicked ${tvViewModel.getTV().id}")
} }
(activity as? MainActivity)?.switchMainFragment() (activity as? MainActivity)?.switchMainFragment()
} }
@@ -410,8 +415,9 @@ class MainFragment : Fragment(), CardAdapter.ItemListener {
Log.i(TAG, "toPosition $rowPosition $itemPosition") Log.i(TAG, "toPosition $rowPosition $itemPosition")
for (i in rowList) { for (i in rowList) {
if (i.tag as Int == rowPosition) { if (i.tag as Int == rowPosition) {
((i as RecyclerView).adapter as CardAdapter).focusable = true ((i as RecyclerView).adapter as CardAdapter).updateEPG()
((i as RecyclerView).adapter as CardAdapter).toPosition(itemPosition!!) (i.adapter as CardAdapter).focusable = true
(i.adapter as CardAdapter).toPosition(itemPosition!!)
break break
} }
} }
@@ -78,10 +78,18 @@ class PlayerFragment : Fragment(), SurfaceHolder.Callback {
override fun onPlayerError(error: PlaybackException) { override fun onPlayerError(error: PlaybackException) {
super.onPlayerError(error) super.onPlayerError(error)
Log.e(TAG, "PlaybackException $error") Log.e(TAG, "PlaybackException $error")
val err = "播放错误"
tvViewModel?.setErrInfo(err)
tvViewModel?.changed("retry") tvViewModel?.changed("retry")
} }
override fun onIsPlayingChanged(isPlaying: Boolean) {
super.onIsPlayingChanged(isPlaying)
if (isPlaying) {
tvViewModel?.setErrInfo("")
}
}
}) })
} }
}) })
@@ -18,7 +18,7 @@ import androidx.core.app.ActivityCompat
import androidx.core.content.PermissionChecker import androidx.core.content.PermissionChecker
import androidx.core.content.PermissionChecker.checkSelfPermission import androidx.core.content.PermissionChecker.checkSelfPermission
import com.lizongying.mytv.api.ReleaseV2 import com.lizongying.mytv.api.ReleaseV2
import com.lizongying.mytv.requests.MyRequest import com.lizongying.mytv.requests.ReleaseRequest
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@@ -32,7 +32,7 @@ class UpdateManager(
) : ) :
ConfirmationFragment.ConfirmationListener { ConfirmationFragment.ConfirmationListener {
private var myRequest = MyRequest() private var myRequest = ReleaseRequest()
private var release: ReleaseV2? = null private var release: ReleaseV2? = null
private var downloadReceiver: DownloadReceiver? = null private var downloadReceiver: DownloadReceiver? = null
@@ -5,6 +5,7 @@ import android.os.Build
import android.util.TypedValue import android.util.TypedValue
import com.google.gson.Gson import com.google.gson.Gson
import com.lizongying.mytv.api.TimeResponse import com.lizongying.mytv.api.TimeResponse
import com.lizongying.mytv.requests.Request
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import java.io.IOException import java.io.IOException
@@ -1,4 +1,4 @@
package com.lizongying.mytv package com.lizongying.mytv.api
import android.content.Context import android.content.Context
@@ -1,7 +1,6 @@
package com.lizongying.mytv.api package com.lizongying.mytv.api
import android.content.Context import android.content.Context
import com.lizongying.mytv.Encryptor
import com.lizongying.mytv.SP import com.lizongying.mytv.SP
import com.lizongying.mytv.Utils.getDateTimestamp import com.lizongying.mytv.Utils.getDateTimestamp
import com.lizongying.mytv.models.TVViewModel import com.lizongying.mytv.models.TVViewModel
@@ -1,4 +1,4 @@
package com.lizongying.mytv package com.lizongying.mytv.models
import com.lizongying.mytv.models.ProgramType import com.lizongying.mytv.models.ProgramType
import java.io.Serializable import java.io.Serializable
@@ -28,6 +28,8 @@ data class TV(
", pid='" + pid + '\'' + ", pid='" + pid + '\'' +
", sid='" + sid + '\'' + ", sid='" + sid + '\'' +
", programType='" + programType + '\'' + ", programType='" + programType + '\'' +
", needToken='" + needToken + '\'' +
", mustToken='" + mustToken + '\'' +
'}' '}'
} }
} }
@@ -1,6 +1,6 @@
package com.lizongying.mytv package com.lizongying.mytv.models
import com.lizongying.mytv.models.ProgramType import com.lizongying.mytv.R
object TVList { object TVList {
val list: Map<String, List<TV>> by lazy { val list: Map<String, List<TV>> by lazy {
@@ -900,6 +900,7 @@ object TVList {
v.forEach { v1 -> v.forEach { v1 ->
if (!v1.mustToken) { if (!v1.mustToken) {
v1.id = id v1.id = id
v1.needToken = false
id++ id++
group.add(v1) group.add(v1)
} }
@@ -16,10 +16,6 @@ class TVListViewModel : ViewModel() {
val itemPosition: LiveData<Int> val itemPosition: LiveData<Int>
get() = _itemPosition get() = _itemPosition
private val _itemPositionCurrent = MutableLiveData<Int>()
val itemPositionCurrent: LiveData<Int>
get() = _itemPositionCurrent
fun addTVViewModel(tvViewModel: TVViewModel) { fun addTVViewModel(tvViewModel: TVViewModel) {
if (_tvListViewModel.value == null) { if (_tvListViewModel.value == null) {
_tvListViewModel.value = mutableListOf(tvViewModel) _tvListViewModel.value = mutableListOf(tvViewModel)
@@ -32,23 +28,15 @@ class TVListViewModel : ViewModel() {
return _tvListViewModel.value?.get(id) return _tvListViewModel.value?.get(id)
} }
fun getTVViewModelCurrent(): TVViewModel? {
return _itemPositionCurrent.value?.let { _tvListViewModel.value?.get(it) }
}
fun setItemPosition(position: Int) { fun setItemPosition(position: Int) {
_itemPosition.value = position _itemPosition.value = position
_itemPositionCurrent.value = position
}
fun setItemPositionCurrent(position: Int) {
_itemPositionCurrent.value = position
} }
fun size(): Int { fun size(): Int {
if (_tvListViewModel.value == null) { if (_tvListViewModel.value == null) {
return 0 return 0
} }
return _tvListViewModel.value!!.size return _tvListViewModel.value!!.size
} }
} }
@@ -1,10 +1,8 @@
package com.lizongying.mytv.models package com.lizongying.mytv.models
import android.util.Log
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import com.lizongying.mytv.TV
import com.lizongying.mytv.api.FEPG import com.lizongying.mytv.api.FEPG
import com.lizongying.mytv.proto.Ysp.cn.yangshipin.omstv.common.proto.programModel.Program import com.lizongying.mytv.proto.Ysp.cn.yangshipin.omstv.common.proto.programModel.Program
import com.tencent.videolite.android.datamodel.cctvjce.TVProgram import com.tencent.videolite.android.datamodel.cctvjce.TVProgram
@@ -56,24 +54,15 @@ class TVViewModel(private var tv: TV) : ViewModel() {
if (_videoUrl.value!!.last().contains("cctv.cn")) { if (_videoUrl.value!!.last().contains("cctv.cn")) {
tv.videoUrl = tv.videoUrl.subList(0, tv.videoUrl.lastIndex) + listOf(url) tv.videoUrl = tv.videoUrl.subList(0, tv.videoUrl.lastIndex) + listOf(url)
} else { } else {
tv.videoUrl = tv.videoUrl + listOf(url) tv.videoUrl += listOf(url)
} }
} else { } else {
tv.videoUrl = tv.videoUrl + listOf(url) tv.videoUrl += listOf(url)
} }
_videoUrl.value = tv.videoUrl _videoUrl.value = tv.videoUrl
_videoIndex.value = tv.videoUrl.lastIndex _videoIndex.value = tv.videoUrl.lastIndex
} }
fun firstSource() {
if (_videoUrl.value!!.isNotEmpty()) {
setVideoIndex(0)
allReady()
} else {
Log.e(TAG, "no first")
}
}
fun changed(from: String) { fun changed(from: String) {
_change.value = from _change.value = from
} }
@@ -82,10 +71,6 @@ class TVViewModel(private var tv: TV) : ViewModel() {
_ready.value = true _ready.value = true
} }
fun setVideoIndex(videoIndex: Int) {
_videoIndex.value = videoIndex
}
init { init {
_videoUrl.value = tv.videoUrl _videoUrl.value = tv.videoUrl
_videoIndex.value = tv.videoUrl.lastIndex _videoIndex.value = tv.videoUrl.lastIndex
@@ -10,7 +10,7 @@ import retrofit2.Response
import kotlin.coroutines.resume import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine import kotlin.coroutines.suspendCoroutine
class MyRequest { class ReleaseRequest {
private var releaseService = ApiClient().releaseService private var releaseService = ApiClient().releaseService
suspend fun getRelease(): ReleaseV2? { suspend fun getRelease(): ReleaseV2? {
@@ -39,6 +39,6 @@ class MyRequest {
} }
companion object { companion object {
private const val TAG = "MyRequest" private const val TAG = "ReleaseRequest"
} }
} }
@@ -1,11 +1,10 @@
package com.lizongying.mytv package com.lizongying.mytv.requests
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
import android.util.Base64 import android.util.Base64
import android.util.Log import android.util.Log
import com.google.gson.Gson import com.lizongying.mytv.Utils
import java.net.URLDecoder
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.Auth import com.lizongying.mytv.api.Auth
@@ -25,6 +24,7 @@ import com.lizongying.mytv.api.YSPBtraceService
import com.lizongying.mytv.api.YSPJceService import com.lizongying.mytv.api.YSPJceService
import com.lizongying.mytv.api.YSPProtoService import com.lizongying.mytv.api.YSPProtoService
import com.lizongying.mytv.api.YSPTokenService import com.lizongying.mytv.api.YSPTokenService
import com.lizongying.mytv.models.TVList
import com.lizongying.mytv.models.TVViewModel import com.lizongying.mytv.models.TVViewModel
import com.lizongying.mytv.proto.Ysp.cn.yangshipin.oms.common.proto.pageModel import com.lizongying.mytv.proto.Ysp.cn.yangshipin.oms.common.proto.pageModel
import com.lizongying.mytv.proto.Ysp.cn.yangshipin.omstv.common.proto.epgProgramModel import com.lizongying.mytv.proto.Ysp.cn.yangshipin.omstv.common.proto.epgProgramModel
@@ -118,11 +118,17 @@ object Request {
} else { } else {
if (!tvModel.getTV().mustToken) { if (!tvModel.getTV().mustToken) {
fetchAuth(tvModel, cookie) fetchAuth(tvModel, cookie)
} else {
// TODO
} }
} }
} else { } else {
fetchAuth(tvModel, cookie) fetchAuth(tvModel, cookie)
} }
} else {
val err = "认证结果错误"
Log.e(TAG, "$title $err")
tvModel.setErrInfo(err)
} }
} }
} else { } else {
@@ -137,11 +143,17 @@ object Request {
} else { } else {
if (!tvModel.getTV().mustToken) { if (!tvModel.getTV().mustToken) {
fetchAuth(tvModel, cookie) fetchAuth(tvModel, cookie)
} else {
// TODO
} }
} }
} else { } else {
fetchAuth(tvModel, cookie) fetchAuth(tvModel, cookie)
} }
} else {
val err = "认证状态错误"
Log.e(TAG, "$title $err")
tvModel.setErrInfo(err)
} }
} }
} }
@@ -158,11 +170,17 @@ object Request {
} else { } else {
if (!tvModel.getTV().mustToken) { if (!tvModel.getTV().mustToken) {
fetchAuth(tvModel, cookie) fetchAuth(tvModel, cookie)
} else {
// TODO
} }
} }
} else { } else {
fetchAuth(tvModel, cookie) fetchAuth(tvModel, cookie)
} }
} else {
val err = "认证请求错误"
Log.e(TAG, "$title $err")
tvModel.setErrInfo(err)
} }
} }
}) })
@@ -171,7 +189,7 @@ object Request {
private fun fetchVideo(tvModel: TVViewModel, cookie: String) { private fun fetchVideo(tvModel: TVViewModel, cookie: String) {
cancelCall() cancelCall()
if (::btraceRunnable.isInitialized) { if (Request::btraceRunnable.isInitialized) {
handler.removeCallbacks(btraceRunnable) handler.removeCallbacks(btraceRunnable)
} }
@@ -229,18 +247,25 @@ object Request {
if (!tvModel.getTV().mustToken) { if (!tvModel.getTV().mustToken) {
fetchVideo(tvModel, cookie) fetchVideo(tvModel, cookie)
// fetchAuth(tvModel, cookie) // fetchAuth(tvModel, cookie)
} else {
// TODO
} }
} }
} else { } else {
fetchVideo(tvModel, cookie) fetchVideo(tvModel, cookie)
// fetchAuth(tvModel, cookie) // fetchAuth(tvModel, cookie)
} }
} else {
val err = "结果错误"
Log.e(TAG, "$title $err")
tvModel.setErrInfo(err)
} }
} }
} else { } else {
if (liveInfo?.data?.errinfo != null && liveInfo.data.errinfo == "应版权方要求,暂停提供直播信号,请点击观看其他精彩节目") { if (liveInfo?.data?.errinfo != null && liveInfo.data.errinfo == "应版权方要求,暂停提供直播信号,请点击观看其他精彩节目") {
Log.e(TAG, "$title error ${liveInfo.data.errinfo}") val err = "版权错误"
tvModel.setErrInfo(liveInfo.data.errinfo) Log.e(TAG, "$title $err")
tvModel.setErrInfo(err)
} else { } else {
Log.e(TAG, "$title url error $request $liveInfo") Log.e(TAG, "$title url error $request $liveInfo")
if (tvModel.retryTimes < tvModel.retryMaxTimes) { if (tvModel.retryTimes < tvModel.retryMaxTimes) {
@@ -255,12 +280,18 @@ object Request {
if (!tvModel.getTV().mustToken) { if (!tvModel.getTV().mustToken) {
fetchVideo(tvModel, cookie) fetchVideo(tvModel, cookie)
// fetchAuth(tvModel, cookie) // fetchAuth(tvModel, cookie)
} else {
// TODO
} }
} }
} else { } else {
fetchVideo(tvModel, cookie) fetchVideo(tvModel, cookie)
// fetchAuth(tvModel, cookie) // fetchAuth(tvModel, cookie)
} }
} else {
val err = "其他错误"
Log.e(TAG, "$title $err")
tvModel.setErrInfo(err)
} }
} }
} }
@@ -278,12 +309,18 @@ object Request {
if (!tvModel.getTV().mustToken) { if (!tvModel.getTV().mustToken) {
fetchVideo(tvModel, cookie) fetchVideo(tvModel, cookie)
// fetchAuth(tvModel, cookie) // fetchAuth(tvModel, cookie)
} else {
// TODO
} }
} }
} else { } else {
fetchVideo(tvModel, cookie) fetchVideo(tvModel, cookie)
// fetchAuth(tvModel, cookie) // fetchAuth(tvModel, cookie)
} }
} else {
val err = "状态错误"
Log.e(TAG, "$title $err")
tvModel.setErrInfo(err)
} }
} }
} }
@@ -300,11 +337,17 @@ object Request {
} else { } else {
if (!tvModel.getTV().mustToken) { if (!tvModel.getTV().mustToken) {
fetchVideo(tvModel, cookie) fetchVideo(tvModel, cookie)
} else {
// TODO
} }
} }
} else { } else {
fetchVideo(tvModel, cookie) fetchVideo(tvModel, cookie)
} }
} else {
val err = "请求错误"
Log.e(TAG, "$title $err")
tvModel.setErrInfo(err)
} }
} }
}) })
@@ -340,6 +383,8 @@ object Request {
val cookie = val cookie =
"versionName=99.99.99; versionCode=999999; vplatform=109; platformVersion=Chrome; deviceModel=120; appid=1400421205; yspappid=519748109" "versionName=99.99.99; versionCode=999999; vplatform=109; platformVersion=Chrome; deviceModel=120; appid=1400421205; yspappid=519748109"
fetchAuth(tvModel, cookie) fetchAuth(tvModel, cookie)
} else {
// TODO
} }
} }
} }
@@ -355,6 +400,8 @@ object Request {
val cookie = val cookie =
"versionName=99.99.99; versionCode=999999; vplatform=109; platformVersion=Chrome; deviceModel=120; appid=1400421205; yspappid=519748109" "versionName=99.99.99; versionCode=999999; vplatform=109; platformVersion=Chrome; deviceModel=120; appid=1400421205; yspappid=519748109"
fetchAuth(tvModel, cookie) fetchAuth(tvModel, cookie)
} else {
// TODO
} }
} }
} }
@@ -397,6 +444,8 @@ object Request {
val cookie = val cookie =
"versionName=99.99.99; versionCode=999999; vplatform=109; platformVersion=Chrome; deviceModel=120; appid=1400421205; yspappid=519748109" "versionName=99.99.99; versionCode=999999; vplatform=109; platformVersion=Chrome; deviceModel=120; appid=1400421205; yspappid=519748109"
fetchVideo(tvModel, cookie) fetchVideo(tvModel, cookie)
} else {
// TODO
} }
} }
} }
@@ -412,6 +461,8 @@ object Request {
val cookie = val cookie =
"versionName=99.99.99; versionCode=999999; vplatform=109; platformVersion=Chrome; deviceModel=120; appid=1400421205; yspappid=519748109" "versionName=99.99.99; versionCode=999999; vplatform=109; platformVersion=Chrome; deviceModel=120; appid=1400421205; yspappid=519748109"
fetchVideo(tvModel, cookie) fetchVideo(tvModel, cookie)
} else {
// TODO
} }
} }
} }
@@ -447,6 +498,10 @@ object Request {
if (tvModel.tokenFHRetryTimes < tvModel.tokenFHRetryMaxTimes) { if (tvModel.tokenFHRetryTimes < tvModel.tokenFHRetryMaxTimes) {
tvModel.tokenFHRetryTimes++ tvModel.tokenFHRetryTimes++
fetchFAuth(tvModel) fetchFAuth(tvModel)
} else {
val err = "状态错误"
Log.e(TAG, "$title $err")
tvModel.setErrInfo(err)
} }
} }
} }
@@ -456,6 +511,10 @@ object Request {
if (tvModel.tokenFHRetryTimes < tvModel.tokenFHRetryMaxTimes) { if (tvModel.tokenFHRetryTimes < tvModel.tokenFHRetryMaxTimes) {
tvModel.tokenFHRetryTimes++ tvModel.tokenFHRetryTimes++
fetchFAuth(tvModel) fetchFAuth(tvModel)
} else {
val err = "请求错误"
Log.e(TAG, "$title $err")
tvModel.setErrInfo(err)
} }
} }
}) })
@@ -817,6 +876,6 @@ object Request {
} }
fun setRequestListener(listener: RequestListener) { fun setRequestListener(listener: RequestListener) {
this.listener = listener Request.listener = listener
} }
} }
+23
View File
@@ -0,0 +1,23 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt"
android:viewportWidth="50"
android:viewportHeight="50"
android:width="62.5dp"
android:height="62.5dp">
<group
android:scaleX="0.1"
android:scaleY="-0.1"
android:translateY="50">
<path
android:pathData="M205 377c-27 -27 -40 -33 -65 -29 -30 4 -70 -19 -70 -40 0 -5 -16 -24 -35 -42 -38 -36 -44 -66 -23 -111 22 -49 51 -55 248 -55l182 0 29 29c46 46 37 106 -20 136 -20 10 -31 25 -35 49 -4 22 -20 46 -42 65 -29 26 -43 31 -85 31 -44 0 -55 -4 -84 -33zm138 2c29 -13 57 -58 57 -93 0 -17 5 -26 15 -26 24 0 65 -46 65 -71 0 -13 -10 -33 -22 -46 -21 -22 -26 -23 -205 -23 -182 0 -184 0 -208 25 -33 32 -32 70 3 105 16 15 36 40 45 54 18 27 54 35 74 15 8 -8 16 -2 29 19 9 17 27 35 38 41 28 13 80 13 109 0z"
android:fillColor="#FFEEEEEE" />
<path
android:pathData="M174 269c-10 -17 13 -36 27 -22 12 12 4 33 -11 33 -5 0 -12 -5 -16 -11z"
android:fillColor="#FFEEEEEE" />
<path
android:pathData="M294 269c-10 -17 13 -36 27 -22 12 12 4 33 -11 33 -5 0 -12 -5 -16 -11z"
android:fillColor="#FFEEEEEE" />
<path
android:pathData="M194 196c-32 -14 -50 -33 -41 -42 3 -3 20 4 38 15 43 26 75 26 118 0 34 -20 49 -20 36 1 -10 16 -69 40 -97 40 -13 -1 -37 -7 -54 -14z"
android:fillColor="#FFEEEEEE" />
</group>
</vector>
+30
View File
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/error"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center_horizontal"
android:gravity="center_vertical|center_horizontal"
android:orientation="vertical" >
<ImageView
android:id="@+id/logo"
android:src="@drawable/sad_cloud"
android:layout_width="50dp"
android:layout_height="50dp" />
<TextView
android:id="@+id/msg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:textColor="#FFEEEEEE"
android:text="Message"
android:textSize="20sp" />
</LinearLayout>
</FrameLayout>
+2 -1
View File
@@ -2,5 +2,6 @@
<color name="black">#000</color> <color name="black">#000</color>
<color name="white">#FFF</color> <color name="white">#FFF</color>
<color name="focus">#0096a6</color> <color name="focus">#0096a6</color>
<color name="blur">#FF263238</color> <color name="blur">#223239</color>
<color name="ic_launcher_background">#223239</color>
</resources> </resources>
@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_background">#223239</color>
</resources>
-22
View File
@@ -1,25 +1,3 @@
<resources> <resources>
<style name="CustomImageCardViewStyle" parent="Widget.Leanback.ImageCardViewStyle">
<item name="cardType">infoUnder</item>
<item name="infoVisibility">always</item>
<!-- In order to keep backward compatibility we have to create an icon on right. -->
<item name="lbImageCardViewType">Title|Content|IconOnRight</item>
<!-- Deprecated. Use 'Widget.Leanback.ImageCardView.InfoAreaStyle' instead. -->
<item name="infoAreaBackground">@null</item>
</style>
<style name="CustomImageCardViewImageStyle" parent="Widget.Leanback.ImageCardView.ImageStyle">
<item name="android:layout_width">150dp</item>
<item name="android:layout_height">40dp</item>
<item name="android:adjustViewBounds">true</item>
<item name="android:contentDescription">@null</item>
<item name="android:scaleType">centerInside</item>
<item name="layout_viewType">main</item>
</style>
<style name="CustomImageCardTheme" parent="Theme.Leanback">
<item name="imageCardViewStyle">@style/CustomImageCardViewStyle</item>
<item name="imageCardViewImageStyle">@style/CustomImageCardViewImageStyle</item>
</style>
</resources> </resources>
-3
View File
@@ -1,8 +1,5 @@
<resources> <resources>
<style name="Theme.MyTV" parent="@style/Theme.Leanback"> <style name="Theme.MyTV" parent="@style/Theme.Leanback">
<item name="browsePaddingStart">11dp</item>
<item name="browsePaddingEnd">11dp</item>
<item name="browseRowsMarginTop">54dp</item>
</style> </style>
</resources> </resources>