From c759ada90730fa2c4574e5aff27e1ce938a55207 Mon Sep 17 00:00:00 2001 From: Li ZongYing Date: Wed, 27 Dec 2023 16:26:05 +0800 Subject: [PATCH] fix still playing after exit --- README.md | 13 ++- .../java/com/lizongying/mytv/MainActivity.kt | 40 +++---- .../java/com/lizongying/mytv/MainFragment.kt | 44 ++++++-- .../com/lizongying/mytv/PlayerFragment.kt | 103 ++++++++++++------ .../main/java/com/lizongying/mytv/TVList.kt | 20 ++++ gradle.properties | 2 +- 6 files changed, 153 insertions(+), 69 deletions(-) diff --git a/README.md b/README.md index 87d70e2..889efcb 100644 --- a/README.md +++ b/README.md @@ -4,13 +4,22 @@ ## 使用 -下载安装[releases](https://github.com/lizongying/my-tv/releases) +下载安装 [releases](https://github.com/lizongying/my-tv/releases/) -[my-tv](https://lyrics.run/my-tv.html) +其他地址 [my-tv](https://lyrics.run/my-tv.html) ![image](./screenshots/img.png) ![image](./screenshots/img_1.png) +## 更新日志 + +### v1.2.4 + +* 改变换台滑动方向,上一个频道下滑,下一个频道上滑 +* 软件退出时,退出播放器 +* 播放相同的频道,不再重复加载 +* 暂时移除部分频道 + ## 其他 小米电视可以使用小米电视助手进行安装 diff --git a/app/src/main/java/com/lizongying/mytv/MainActivity.kt b/app/src/main/java/com/lizongying/mytv/MainActivity.kt index a3e2790..403f195 100644 --- a/app/src/main/java/com/lizongying/mytv/MainActivity.kt +++ b/app/src/main/java/com/lizongying/mytv/MainActivity.kt @@ -27,7 +27,7 @@ import java.security.MessageDigest class MainActivity : FragmentActivity() { - private val playerFragment = PlayerFragment() + var playerFragment = PlayerFragment() private val mainFragment = MainFragment() private val infoFragment = InfoFragment() @@ -88,11 +88,11 @@ class MainActivity : FragmentActivity() { mainFragment.next() } - fun prevSource() { + private fun prevSource() { mainFragment.prevSource() } - fun nextSource() { + private fun nextSource() { mainFragment.nextSource() } @@ -100,7 +100,7 @@ class MainActivity : FragmentActivity() { val transaction = supportFragmentManager.beginTransaction() if (mainFragment.isHidden) { - focusMainFragment() +// focusMainFragment() transaction.show(mainFragment) } else { transaction.hide(mainFragment) @@ -113,7 +113,7 @@ class MainActivity : FragmentActivity() { mainFragment.focus() } - fun mainFragmentIsHidden(): Boolean { + private fun mainFragmentIsHidden(): Boolean { return mainFragment.isHidden } @@ -126,7 +126,6 @@ class MainActivity : FragmentActivity() { } override fun onTouchEvent(event: MotionEvent?): Boolean { - // 在触摸事件中将事件传递给 GestureDetector 处理手势 if (event != null) { gestureDetector.onTouchEvent(event) } @@ -147,30 +146,27 @@ class MainActivity : FragmentActivity() { velocityX: Float, velocityY: Float ): Boolean { - // 如果 Y 方向的速度为负值,表示向上滑动 - if (velocityY < 0) { - // 在这里执行上滑时的操作 + if (velocityY > 0) { if (mainFragment.isHidden) { prev() } else { - if (mainFragment.selectedPosition == 0) { - mainFragment.setSelectedPosition( - mainFragment.tvListViewModel.maxNum.size - 1, - false - ) - } +// if (mainFragment.selectedPosition == 0) { +// mainFragment.setSelectedPosition( +// mainFragment.tvListViewModel.maxNum.size - 1, +// false +// ) +// } } } - if (velocityY > 0) { - // 在这里执行上滑时的操作 + if (velocityY < 0) { if (mainFragment.isHidden) { next() } else { - if (mainFragment.selectedPosition == mainFragment.tvListViewModel.maxNum.size - 1) { -// mainFragment.setSelectedPosition(0, false) - hideMainFragment() - return false - } +// if (mainFragment.selectedPosition == mainFragment.tvListViewModel.maxNum.size - 1) { +//// mainFragment.setSelectedPosition(0, false) +// hideMainFragment() +// return false +// } } } return super.onFling(e1, e2, velocityX, velocityY) diff --git a/app/src/main/java/com/lizongying/mytv/MainFragment.kt b/app/src/main/java/com/lizongying/mytv/MainFragment.kt index 5a8c726..d825f71 100644 --- a/app/src/main/java/com/lizongying/mytv/MainFragment.kt +++ b/app/src/main/java/com/lizongying/mytv/MainFragment.kt @@ -4,9 +4,6 @@ import android.content.Context import android.content.SharedPreferences import android.os.Bundle import android.util.Log -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup import android.widget.Toast import androidx.leanback.app.BrowseSupportFragment import androidx.leanback.widget.ArrayObjectAdapter @@ -36,6 +33,9 @@ class MainFragment : BrowseSupportFragment() { var tvListViewModel = TVListViewModel() private var sharedPref: SharedPreferences? = null + + private var lastVideoUrl: String = "" + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) headersState = HEADERS_DISABLED @@ -56,19 +56,23 @@ class MainFragment : BrowseSupportFragment() { } tvListViewModel.getTVListViewModel().value?.forEach { tvViewModel -> tvViewModel.ready.observe(viewLifecycleOwner) { _ -> - if (tvViewModel.ready.value != null) { + + // not first time && channel not change + if (tvViewModel.ready.value != null + && tvViewModel.id.value == itemPosition + && check(tvViewModel) + ) { Log.i(TAG, "ready ${tvViewModel.title.value}") - if (tvViewModel.id.value == itemPosition) { - (activity as? MainActivity)?.play(tvViewModel) -// (activity as? MainActivity)?.switchInfoFragment(tv) - } + (activity as? MainActivity)?.play(tvViewModel) +// (activity as? MainActivity)?.switchInfoFragment(item) } } tvViewModel.change.observe(viewLifecycleOwner) { _ -> - if (tvViewModel.change.value != null) { - Log.i(TAG, "switch to ${tvViewModel.title.value}") + if (tvViewModel.change.value != null && check(tvViewModel)) { + val title = tvViewModel.title.value + Log.i(TAG, "switch $title") if (tvViewModel.ysp() != null) { - Log.i(TAG, "${tvViewModel.title.value} to get ysp") + Log.i(TAG, "request $title") lifecycleScope.launch(Dispatchers.IO) { tvViewModel.let { request?.fetchData(it) } } @@ -82,7 +86,7 @@ class MainFragment : BrowseSupportFragment() { ) Toast.makeText( activity, - tvViewModel.title.value, + title, Toast.LENGTH_SHORT ).show() } @@ -98,6 +102,22 @@ class MainFragment : BrowseSupportFragment() { } } + fun check(tvViewModel: TVViewModel): Boolean { + val title = tvViewModel.title.value + val videoUrl = tvViewModel.videoIndex.value?.let { tvViewModel.videoUrl.value?.get(it) } + if (videoUrl == null || videoUrl == "") { + Log.e(TAG, "$title videoUrl is empty") + return false + } + + if (videoUrl == lastVideoUrl) { + Log.e(TAG, "$title videoUrl is duplication") + return false + } + + return true + } + fun toLastPosition() { setSelectedPosition( selectedPosition, false, diff --git a/app/src/main/java/com/lizongying/mytv/PlayerFragment.kt b/app/src/main/java/com/lizongying/mytv/PlayerFragment.kt index 826d152..7c5ae0c 100644 --- a/app/src/main/java/com/lizongying/mytv/PlayerFragment.kt +++ b/app/src/main/java/com/lizongying/mytv/PlayerFragment.kt @@ -5,9 +5,11 @@ import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.view.ViewTreeObserver import androidx.annotation.OptIn import androidx.fragment.app.Fragment import androidx.media3.common.MediaItem +import androidx.media3.common.PlaybackException import androidx.media3.common.Player import androidx.media3.common.VideoSize import androidx.media3.common.util.UnstableApi @@ -19,10 +21,10 @@ import com.lizongying.mytv.models.TVViewModel class PlayerFragment : Fragment() { - private var lastVideoUrl: String = "" - private var _binding: PlayerBinding? = null private var playerView: PlayerView? = null + private var videoUrl: String? = null + private var tvViewModel: TVViewModel? = null override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -30,43 +32,80 @@ class PlayerFragment : Fragment() { ): View { _binding = PlayerBinding.inflate(inflater, container, false) playerView = _binding!!.playerView + (activity as MainActivity).playerFragment = this + playerView?.viewTreeObserver?.addOnGlobalLayoutListener(object : + ViewTreeObserver.OnGlobalLayoutListener { + override fun onGlobalLayout() { + playerView!!.viewTreeObserver.removeOnGlobalLayoutListener(this) + playerView!!.player = activity?.let { + ExoPlayer.Builder(it) + .build() + } + playerView!!.player?.playWhenReady = true + playerView!!.player?.addListener(object : Player.Listener { + override fun onVideoSizeChanged(videoSize: VideoSize) { + val aspectRatio = 16f / 9f + val layoutParams = playerView?.layoutParams + layoutParams?.width = + (playerView?.measuredHeight?.times(aspectRatio))?.toInt() + playerView?.layoutParams = layoutParams + } +// +// override fun onPlayerError(error: PlaybackException) { +// super.onPlayerError(error) +// } + }) + if (videoUrl !== null) { + playerView!!.player?.run { + videoUrl?.let { MediaItem.fromUri(it) }?.let { setMediaItem(it) } + prepare() + } + videoUrl = null + } + } + }) + Log.i(TAG, "PlayerFragment onCreateView") return _binding!!.root } @OptIn(UnstableApi::class) - fun play(tvModel: TVViewModel) { - val videoUrl = tvModel.videoIndex.value?.let { tvModel.videoUrl.value?.get(it) } - if (videoUrl == null || videoUrl == "") { - Log.e(TAG, "${tvModel.title.value} videoUrl is empty") - return - } - - if (videoUrl == lastVideoUrl) { - Log.e(TAG, "videoUrl is duplication") - return - } - - lastVideoUrl = videoUrl - - if (playerView!!.player == null) { - playerView!!.player = activity?.let { - ExoPlayer.Builder(it) - .build() + fun play(tvViewModel: TVViewModel) { + this.tvViewModel = tvViewModel + val videoUrlCurrent = + tvViewModel.videoIndex.value?.let { tvViewModel.videoUrl.value?.get(it) } + if (playerView == null || playerView?.player == null) { + Log.i(TAG, "playerView not ready $view}") + videoUrl = videoUrlCurrent + } else { + Log.i(TAG, "playerView ok") + playerView?.player?.run { + val mediaItem = MediaItem.Builder() + tvViewModel.id.value?.let { mediaItem.setMediaId(it.toString()) } + videoUrlCurrent?.let { mediaItem.setUri(it) } + setMediaItem(mediaItem.build()) + prepare() } - playerView!!.player?.playWhenReady = true - playerView!!.player?.addListener(object : Player.Listener { - override fun onVideoSizeChanged(videoSize: VideoSize) { - val aspectRatio = 16f / 9f - val layoutParams = playerView?.layoutParams - layoutParams?.width = (playerView?.measuredHeight?.times(aspectRatio))?.toInt() - playerView?.layoutParams = layoutParams - } - }) } + } - playerView!!.player?.run { - setMediaItem(MediaItem.fromUri(videoUrl)) - prepare() + override fun onPause() { + super.onPause() + if (playerView != null) { + playerView!!.player?.stop() + } + } + + override fun onResume() { + super.onResume() + if (playerView != null) { + playerView!!.player?.play() + } + } + + override fun onDestroy() { + super.onDestroy() + if (playerView != null) { + playerView!!.player?.release() } } diff --git a/app/src/main/java/com/lizongying/mytv/TVList.kt b/app/src/main/java/com/lizongying/mytv/TVList.kt index 4a43698..5bd6351 100644 --- a/app/src/main/java/com/lizongying/mytv/TVList.kt +++ b/app/src/main/java/com/lizongying/mytv/TVList.kt @@ -86,6 +86,26 @@ CGTN 纪录频道,https://livedoc.cgtn.com/500d/prog_index.m3u8,https://resource 浙江少儿,http://hw-m-l.cztv.com/channels/lantian/channel008/1080p.m3u8 移动专区 + + +天津卫视,http://ottrrs.hl.chinamobile.com/PLTV/88888888/224/3221225740/index.m3u8;http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226204/index.m3u8 +吉林卫视,http://ottrrs.hl.chinamobile.com/PLTV/88888888/224/3221226397/index.m3u8;http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225792/index.m3u8 +云南卫视,http://ottrrs.hl.chinamobile.com/PLTV/88888888/224/3221226444/index.m3u8;http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225751/index.m3u8 +内蒙古卫视,http://ottrrs.hl.chinamobile.com/PLTV/88888888/224/3221226389/index.m3u8;http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225786/index.m3u8 +新疆卫视,http://ottrrs.hl.chinamobile.com/PLTV/88888888/224/3221226460/index.m3u8;http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225747/index.m3u8 +甘肃卫视,http://ottrrs.hl.chinamobile.com/PLTV/88888888/224/3221225633/index.m3u8;http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225754/index.m3u8 +青海卫视,http://stream.qhbtv.com/qhws/sd/live.m3u8 +陕西卫视,http://ottrrs.hl.chinamobile.com/PLTV/88888888/224/3221226457/index.m3u8;http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225821/index.m3u8 +西藏卫视,http://39.134.24.161/dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226212/index.m3u8;http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226212/index.m3u8 +山西卫视,http://39.134.24.161/dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225763/index.m3u8;http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225763/index.m3u8 +宁夏卫视,http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225748/index.m3u8 +安多卫视,http://stream.qhbtv.com/adws/sd/live.m3u8;http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226228/index.m3u8 +三沙卫视,https://pullsstv90080111.ssws.tv/live/SSTV20220729.m3u8 +延边卫视,http://live.ybtvyun.com/video/s10006-44f040627ca1/index.m3u8;http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226220/index.m3u8 +浙江少儿,http://hw-m-l.cztv.com/channels/lantian/channel008/1080p.m3u8 + + + CETV1,http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225753/index.m3u8 CETV2,http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225756/index.m3u8 CETV3,http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226226/index.m3u8 diff --git a/gradle.properties b/gradle.properties index a2e90d8..c4e19a5 100644 --- a/gradle.properties +++ b/gradle.properties @@ -21,5 +21,5 @@ kotlin.code.style=official # resources declared in the library itself and none from the library's dependencies, # thereby reducing the size of the R class for that library android.nonTransitiveRClass=true -android.defaults.buildfeatures.buildconfig=true +#android.defaults.buildfeatures.buildconfig=true android.nonFinalResIds=false \ No newline at end of file