Compare commits

...
11 Commits
Author SHA1 Message Date
Li ZongYing 230e4fea2b action sign 2024-01-10 23:14:49 +08:00
Li ZongYing 0d26912321 action sign 2024-01-10 23:12:35 +08:00
Li ZongYing af9ff5c8dd action sign 2024-01-10 22:39:49 +08:00
Li ZongYing f0f43e0fda dns cache 2024-01-10 22:11:13 +08:00
Li ZongYing 61f62121f2 menu auto close 2024-01-10 18:01:25 +08:00
Li ZongYing d0c7627e35 fix 13 2024-01-08 22:40:56 +08:00
Li ZongYing c10d8b688f add retry 2024-01-08 20:07:53 +08:00
Li ZongYing 0bfac7d679 cctv8k 2024-01-07 21:37:51 +08:00
Li ZongYing c49246f5c7 cctv8k 2024-01-07 21:36:08 +08:00
Li ZongYing 930c7957ee get token on switch 2024-01-05 18:24:44 +08:00
Li ZongYing 57d42bc917 support vip 2024-01-05 14:53:54 +08:00
27 changed files with 316 additions and 214 deletions
+3
View File
@@ -33,6 +33,9 @@ jobs:
signingKeyBase64: ${{ secrets.KEYSTORE }} signingKeyBase64: ${{ secrets.KEYSTORE }}
keyStorePassword: ${{ secrets.KEYSTORE_PASSWORD }} keyStorePassword: ${{ secrets.KEYSTORE_PASSWORD }}
keyPassword: ${{ secrets.ALIAS_PASSWORD }} keyPassword: ${{ secrets.ALIAS_PASSWORD }}
# env:
# override default build-tools version (29.0.3) -- optional
# BUILD_TOOLS_VERSION: "30.0.2"
- name: Create Release - name: Create Release
id: create_release id: create_release
+10
View File
@@ -14,6 +14,16 @@
## 更新日志 ## 更新日志
### v1.3.3
* 部分错误会提示用户
* 菜单3秒钟后自动关闭
### v1.3.2
* 增加重试,减少因网络问题导致的播放失败
* 优化横幅banner
### v1.2.6 ### v1.2.6
* 支持安卓4.2 * 支持安卓4.2
+1
View File
@@ -6,6 +6,7 @@ plugins {
android { android {
namespace 'com.lizongying.mytv' namespace 'com.lizongying.mytv'
compileSdk 33 compileSdk 33
buildToolsVersion "29.0.3"
viewBinding { viewBinding {
enabled = true enabled = true
+1 -2
View File
@@ -12,12 +12,11 @@
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="@string/app_name" android:label="@string/app_name"
android:supportsRtl="true" android:supportsRtl="true"
android:usesCleartextTraffic="true"
android:theme="@style/Theme.MyTV"> android:theme="@style/Theme.MyTV">
<activity <activity
android:keepScreenOn="true" android:keepScreenOn="true"
android:name=".MainActivity" android:name=".MainActivity"
android:banner="@drawable/logo" android:banner="@drawable/banner"
android:exported="true" android:exported="true"
android:icon="@drawable/logo" android:icon="@drawable/logo"
android:logo="@drawable/logo" android:logo="@drawable/logo"
Binary file not shown.
Binary file not shown.
@@ -32,10 +32,17 @@ class CardPresenter(
cardView.tag = tvViewModel.videoUrl.value cardView.tag = tvViewModel.videoUrl.value
if (tvViewModel.logo.value != null) { if (tvViewModel.logo.value != null) {
Glide.with(viewHolder.view.context) if (tvViewModel.title.value == "CCTV8K 超高清") {
.load(tvViewModel.logo.value) Glide.with(viewHolder.view.context)
.centerInside() .load(R.drawable.cctv8k)
.into(cardView.mainImageView) .centerInside()
.into(cardView.mainImageView)
} else {
Glide.with(viewHolder.view.context)
.load(tvViewModel.logo.value)
.centerInside()
.into(cardView.mainImageView)
}
cardView.setBackgroundColor(Color.WHITE) cardView.setBackgroundColor(Color.WHITE)
cardView.setMainImageScaleType(ImageView.ScaleType.CENTER_INSIDE) cardView.setMainImageScaleType(ImageView.ScaleType.CENTER_INSIDE)
@@ -36,9 +36,16 @@ class InfoFragment : Fragment() {
fun show(tvViewModel: TVViewModel) { fun show(tvViewModel: TVViewModel) {
binding.textView.text = tvViewModel.title.value binding.textView.text = tvViewModel.title.value
Glide.with(this) if (tvViewModel.title.value == "CCTV8K 超高清") {
.load(tvViewModel.logo.value) Glide.with(this)
.into(binding.infoLogo) .load(R.drawable.cctv8k)
.into(binding.infoLogo)
} else {
Glide.with(this)
.load(tvViewModel.logo.value)
.into(binding.infoLogo)
}
val program = tvViewModel.getProgramOne() val program = tvViewModel.getProgramOne()
if (program != null) { if (program != null) {
binding.infoDesc.text = program.name binding.infoDesc.text = program.name
@@ -35,6 +35,9 @@ class MainActivity : FragmentActivity() {
private lateinit var gestureDetector: GestureDetector private lateinit var gestureDetector: GestureDetector
private val handler = Handler()
private val delay: Long = 3000
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main) setContentView(R.layout.activity_main)
@@ -86,6 +89,7 @@ class MainActivity : FragmentActivity() {
if (mainFragment.isHidden) { if (mainFragment.isHidden) {
transaction.show(mainFragment) transaction.show(mainFragment)
keepRunnable()
} else { } else {
transaction.hide(mainFragment) transaction.hide(mainFragment)
} }
@@ -93,6 +97,15 @@ class MainActivity : FragmentActivity() {
transaction.commit() transaction.commit()
} }
fun keepRunnable() {
handler.removeCallbacks(hideRunnable)
handler.postDelayed(hideRunnable, delay)
}
private val hideRunnable = Runnable {
supportFragmentManager.beginTransaction().hide(mainFragment).commit()
}
private fun mainFragmentIsHidden(): Boolean { private fun mainFragmentIsHidden(): Boolean {
return mainFragment.isHidden return mainFragment.isHidden
} }
@@ -6,7 +6,7 @@ import android.os.Bundle
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
import android.util.Log import android.util.Log
import android.view.View import android.widget.Toast
import androidx.leanback.app.BrowseSupportFragment import androidx.leanback.app.BrowseSupportFragment
import androidx.leanback.widget.ArrayObjectAdapter import androidx.leanback.widget.ArrayObjectAdapter
import androidx.leanback.widget.HeaderItem import androidx.leanback.widget.HeaderItem
@@ -29,7 +29,7 @@ import kotlinx.coroutines.launch
class MainFragment : BrowseSupportFragment() { class MainFragment : BrowseSupportFragment() {
var itemPosition: Int = 0 var itemPosition: Int = 0
private var request: Request? = null private var request: Request = Request()
private var rowsAdapter: ArrayObjectAdapter? = null private var rowsAdapter: ArrayObjectAdapter? = null
@@ -52,9 +52,9 @@ class MainFragment : BrowseSupportFragment() {
override fun onActivityCreated(savedInstanceState: Bundle?) { override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState) super.onActivityCreated(savedInstanceState)
sharedPref = activity?.getPreferences(Context.MODE_PRIVATE) activity?.let { request.initYSP(it) }
request = activity?.let { Request(it) } sharedPref = activity?.getPreferences(Context.MODE_PRIVATE)
loadRows() loadRows()
@@ -64,6 +64,13 @@ class MainFragment : BrowseSupportFragment() {
handler.post(mUpdateProgramRunnable) handler.post(mUpdateProgramRunnable)
tvListViewModel.getTVListViewModel().value?.forEach { tvViewModel -> tvListViewModel.getTVListViewModel().value?.forEach { tvViewModel ->
tvViewModel.errInfo.observe(viewLifecycleOwner) { _ ->
if (tvViewModel.errInfo.value != null
&& tvViewModel.id.value == itemPosition
) {
Toast.makeText(context, tvViewModel.errInfo.value, Toast.LENGTH_SHORT).show()
}
}
tvViewModel.ready.observe(viewLifecycleOwner) { _ -> tvViewModel.ready.observe(viewLifecycleOwner) { _ ->
// not first time && channel not change // not first time && channel not change
@@ -79,10 +86,10 @@ class MainFragment : BrowseSupportFragment() {
if (tvViewModel.change.value != null) { if (tvViewModel.change.value != null) {
val title = tvViewModel.title.value val title = tvViewModel.title.value
Log.i(TAG, "switch $title") Log.i(TAG, "switch $title")
if (tvViewModel.pid.value != null) { if (tvViewModel.pid.value != "") {
Log.i(TAG, "request $title") Log.i(TAG, "request $title ${tvViewModel.pid.value}")
lifecycleScope.launch(Dispatchers.IO) { lifecycleScope.launch(Dispatchers.IO) {
tvViewModel.let { request?.fetchData(it) } tvViewModel.let { request.fetchData(it) }
} }
(activity as? MainActivity)?.showInfoFragment(tvViewModel) (activity as? MainActivity)?.showInfoFragment(tvViewModel)
setSelectedPosition( setSelectedPosition(
@@ -107,10 +114,6 @@ class MainFragment : BrowseSupportFragment() {
fragmentReady() fragmentReady()
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
}
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
handler.removeCallbacks(mUpdateProgramRunnable) handler.removeCallbacks(mUpdateProgramRunnable)
@@ -125,11 +128,11 @@ class MainFragment : BrowseSupportFragment() {
if (timestamp - tvViewModel.programUpdateTime > 60) { if (timestamp - tvViewModel.programUpdateTime > 60) {
if (tvViewModel.program.value!!.isEmpty()) { if (tvViewModel.program.value!!.isEmpty()) {
tvViewModel.programUpdateTime = timestamp tvViewModel.programUpdateTime = timestamp
request?.fetchProgram(tvViewModel) request.fetchProgram(tvViewModel)
} else { } else {
if (timestamp - tvViewModel.program.value!!.last().et < 600) { if (timestamp - tvViewModel.program.value!!.last().et < 600) {
tvViewModel.programUpdateTime = timestamp tvViewModel.programUpdateTime = timestamp
request?.fetchProgram(tvViewModel) request.fetchProgram(tvViewModel)
} }
} }
} }
@@ -214,10 +217,7 @@ class MainFragment : BrowseSupportFragment() {
ready++ ready++
Log.i(TAG, "ready $ready") Log.i(TAG, "ready $ready")
if (ready == 3) { if (ready == 3) {
// request.fetchPage()
// request?.fetchPage()
// tvListViewModel.getTVViewModel(0)?.let { request?.fetchProgram(it) }
val tvViewModel = tvListViewModel.getTVViewModel(itemPosition) val tvViewModel = tvListViewModel.getTVViewModel(itemPosition)
tvViewModel?.changed() tvViewModel?.changed()
@@ -281,10 +281,6 @@ class MainFragment : BrowseSupportFragment() {
} }
} }
fun tvViewModel(): TVViewModel? {
return tvListViewModel.getTVViewModel(itemPosition)
}
private fun setupEventListeners() { private fun setupEventListeners() {
onItemViewClickedListener = ItemViewClickedListener() onItemViewClickedListener = ItemViewClickedListener()
onItemViewSelectedListener = ItemViewSelectedListener() onItemViewSelectedListener = ItemViewSelectedListener()
@@ -317,6 +313,7 @@ class MainFragment : BrowseSupportFragment() {
) { ) {
if (item is TVViewModel) { if (item is TVViewModel) {
tvListViewModel.setItemPositionCurrent(item.id.value!!) tvListViewModel.setItemPositionCurrent(item.id.value!!)
(activity as MainActivity).keepRunnable()
} }
} }
} }
@@ -14,9 +14,6 @@ import androidx.media3.common.Player
import androidx.media3.common.VideoSize import androidx.media3.common.VideoSize
import androidx.media3.common.util.UnstableApi import androidx.media3.common.util.UnstableApi
import androidx.media3.exoplayer.ExoPlayer import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.exoplayer.analytics.AnalyticsListener
import androidx.media3.exoplayer.source.LoadEventInfo
import androidx.media3.exoplayer.source.MediaLoadData
import androidx.media3.ui.PlayerView import androidx.media3.ui.PlayerView
import com.lizongying.mytv.databinding.PlayerBinding import com.lizongying.mytv.databinding.PlayerBinding
import com.lizongying.mytv.models.TVViewModel import com.lizongying.mytv.models.TVViewModel
@@ -80,71 +77,8 @@ class PlayerFragment : Fragment() {
val videoUrlCurrent = val videoUrlCurrent =
tvViewModel.videoIndex.value?.let { tvViewModel.videoUrl.value?.get(it) } tvViewModel.videoIndex.value?.let { tvViewModel.videoUrl.value?.get(it) }
playerView?.player?.run { playerView?.player?.run {
val mediaItem = MediaItem.Builder() videoUrlCurrent?.let { setMediaItem(MediaItem.fromUri(it)) }
tvViewModel.id.value?.let { mediaItem.setMediaId(it.toString()) }
videoUrlCurrent?.let { mediaItem.setUri(it) }
setMediaItem(mediaItem.build())
prepare() prepare()
// val httpDataSource = DefaultHttpDataSource.Factory()
// val hls = HlsMediaSource.Factory(httpDataSource).createMediaSource(
// MediaItem.fromUri(
// Uri.parse(videoUrlCurrent)
// )
// )
// val analyticsListener: AnalyticsListener= MyAnalyticsListener()
// val exoPlayer = playerView?.player as ExoPlayer
// exoPlayer.addAnalyticsListener(analyticsListener)
// exoPlayer.setMediaSource(hls)
// exoPlayer.playWhenReady = true
//
//
// exoPlayer.let {
// val parameters =
// TrackSelectionParameters.Builder().setPreferredAudioMimeType("application/id3").build()
// // 更新轨道选择器参数
// exoPlayer.trackSelector?.parameters = parameters
// Log.i(TAG, "parameters $parameters")
// }
//
// // 获取当前轨道组
//
// playerView?.player = exoPlayer
// playerView?.player?.prepare()
//
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
// val codecList = MediaCodecList(MediaCodecList.ALL_CODECS)
// val codecInfos = codecList.codecInfos
//
// for (codecInfo in codecInfos) {
//
// val supportedTypes = codecInfo.supportedTypes
// for (type in supportedTypes) {
// Log.d("supportedTypes", "$type")
//// if (type.equals(androidx.media3.exoplayer.mediacode, ignoreCase = true)) {
//// Log.d("AudioCodecChecker", "Device supports MPEG-L2")
//// return
//// }
// }
// }
//
// Log.d("AudioCodecChecker", "Device does not support MPEG-L2")
// }
}
}
@UnstableApi
class MyAnalyticsListener : AnalyticsListener {
override fun onLoadStarted(
eventTime: AnalyticsListener.EventTime,
loadEventInfo: LoadEventInfo,
mediaLoadData: MediaLoadData
) {
super.onLoadStarted(eventTime, loadEventInfo, mediaLoadData)
// Log.i(TAG, "loadEventInfo.uri ${loadEventInfo.uri} ${mediaLoadData.trackFormat.toString()}")
} }
} }
@@ -7,14 +7,14 @@ import android.util.Base64
import android.util.Log import android.util.Log
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.BtraceClient import com.lizongying.mytv.api.Info
import com.lizongying.mytv.api.LiveInfo import com.lizongying.mytv.api.LiveInfo
import com.lizongying.mytv.api.LiveInfoRequest import com.lizongying.mytv.api.LiveInfoRequest
import com.lizongying.mytv.api.ProtoClient
import com.lizongying.mytv.api.YSP import com.lizongying.mytv.api.YSP
import com.lizongying.mytv.api.YSPApiService import com.lizongying.mytv.api.YSPApiService
import com.lizongying.mytv.api.YSPBtraceService import com.lizongying.mytv.api.YSPBtraceService
import com.lizongying.mytv.api.YSPProtoService import com.lizongying.mytv.api.YSPProtoService
import com.lizongying.mytv.api.YSPTokenService
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
@@ -26,11 +26,12 @@ import javax.crypto.spec.IvParameterSpec
import javax.crypto.spec.SecretKeySpec import javax.crypto.spec.SecretKeySpec
class Request(var context: Context) { class 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 ysp: YSP? = null private var ysp: YSP? = null
private var yspApiService: YSPApiService? = null
private var yspBtraceService: YSPBtraceService? = null
private var yspProtoService: YSPProtoService? = null
// TODO onDestroy // TODO onDestroy
private val handler = Handler(Looper.getMainLooper()) private val handler = Handler(Looper.getMainLooper())
@@ -59,7 +60,6 @@ class Request(var context: Context) {
"CGTN阿拉伯语频道" to "CGTN 阿拉伯语频道", "CGTN阿拉伯语频道" to "CGTN 阿拉伯语频道",
"CGTN西班牙语频道" to "CGTN 西班牙语频道", "CGTN西班牙语频道" to "CGTN 西班牙语频道",
"CGTN外语纪录频道" to "CGTN 纪录频道", "CGTN外语纪录频道" to "CGTN 纪录频道",
"东方卫视" to "东方卫视", "东方卫视" to "东方卫视",
"湖南卫视" to "湖南卫视", "湖南卫视" to "湖南卫视",
"湖北卫视" to "湖北卫视", "湖北卫视" to "湖北卫视",
@@ -83,26 +83,22 @@ class Request(var context: Context) {
"海南卫视" to "海南卫视", "海南卫视" to "海南卫视",
) )
init { fun initYSP(context: Context) {
if (context is MainActivity) { ysp = YSP(context)
ysp = YSP(context)
}
yspApiService = ApiClient().yspApiService
yspBtraceService = BtraceClient().yspBtraceService
yspProtoService = ProtoClient().yspProtoService
} }
fun fetchData(tvModel: TVViewModel) { fun fetchVideo(tvModel: TVViewModel, cookie: String) {
if (::myRunnable.isInitialized) { if (::myRunnable.isInitialized) {
handler.removeCallbacks(myRunnable) handler.removeCallbacks(myRunnable)
} }
tvModel.seq = 0
val data = ysp?.switch(tvModel)
val title = tvModel.title.value val title = tvModel.title.value
tvModel.seq = 0
val data = ysp?.switch(tvModel)
val request = data?.let { LiveInfoRequest(it) } val request = data?.let { LiveInfoRequest(it) }
request?.let { yspApiService?.getLiveInfo(it) }
request?.let { yspApiService.getLiveInfo(cookie, it) }
?.enqueue(object : Callback<LiveInfo> { ?.enqueue(object : Callback<LiveInfo> {
override fun onResponse(call: Call<LiveInfo>, response: Response<LiveInfo>) { override fun onResponse(call: Call<LiveInfo>, response: Response<LiveInfo>) {
if (response.isSuccessful) { if (response.isSuccessful) {
@@ -127,30 +123,86 @@ class Request(var context: Context) {
Log.i(TAG, "$title url $url") Log.i(TAG, "$title url $url")
tvModel.addVideoUrl(url) tvModel.addVideoUrl(url)
tvModel.allReady() tvModel.allReady()
tvModel.retryTimes = 0
myRunnable = MyRunnable(tvModel) myRunnable = MyRunnable(tvModel)
handler.post(myRunnable) handler.post(myRunnable)
} else { } else {
Log.e(TAG, "$title key error") Log.e(TAG, "$title key error")
tvModel.firstSource() if (tvModel.retryTimes < tvModel.retryMaxTimes) {
tvModel.retryTimes++
fetchVideo(tvModel, cookie)
}
} }
} else { } else {
Log.e(TAG, "$title url error $request") if (liveInfo?.data?.errinfo != null && liveInfo.data.errinfo == "应版权方要求,暂停提供直播信号,请点击观看其他精彩节目") {
tvModel.firstSource() Log.e(TAG, "$title error ${liveInfo.data.errinfo}")
tvModel.setErrInfo(liveInfo.data.errinfo)
} else {
Log.e(TAG, "$title url error $request $liveInfo")
if (tvModel.retryTimes < tvModel.retryMaxTimes) {
tvModel.retryTimes++
fetchVideo(tvModel, cookie)
}
}
} }
} else { } else {
Log.e(TAG, "$title status error") Log.e(TAG, "$title status error")
tvModel.firstSource() if (tvModel.retryTimes < tvModel.retryMaxTimes) {
tvModel.retryTimes++
fetchVideo(tvModel, cookie)
}
} }
} }
override fun onFailure(call: Call<LiveInfo>, t: Throwable) { override fun onFailure(call: Call<LiveInfo>, t: Throwable) {
Log.e(TAG, "$title request error") Log.e(TAG, "$title request error")
tvModel.firstSource() if (tvModel.retryTimes < tvModel.retryMaxTimes) {
tvModel.retryTimes++
fetchVideo(tvModel, cookie)
}
} }
}) })
} }
fun fetchVideo(tvModel: TVViewModel) {
yspTokenService.getInfo()
.enqueue(object : Callback<Info> {
override fun onResponse(call: Call<Info>, response: Response<Info>) {
if (response.isSuccessful) {
val info = response.body()
val token = info?.data?.token
Log.i(TAG, "info success $token")
val cookie =
"guid=1; vplatform=109; yspopenid=vu0-8lgGV2LW9QjDeuBFsX8yMnzs37Q3_HZF6XyVDpGR_I; vusession=$token"
fetchVideo(tvModel, cookie)
} else {
Log.e(TAG, "info status error")
if (tvModel.retryTimes < tvModel.retryMaxTimes) {
tvModel.retryTimes++
fetchVideo(tvModel)
}
}
}
override fun onFailure(call: Call<Info>, t: Throwable) {
Log.e(TAG, "info request error $t")
if (tvModel.retryTimes < tvModel.retryMaxTimes) {
tvModel.retryTimes++
fetchVideo(tvModel)
}
}
})
}
fun fetchData(tvModel: TVViewModel) {
if (tvModel.needToken) {
fetchVideo(tvModel)
} else {
val cookie = "guid=1; vplatform=109"
fetchVideo(tvModel, cookie)
}
}
inner class MyRunnable(private val tvModel: TVViewModel) : Runnable { inner class MyRunnable(private val tvModel: TVViewModel) : Runnable {
override fun run() { override fun run() {
fetchBtrace(tvModel) fetchBtrace(tvModel)
@@ -164,7 +216,7 @@ class Request(var context: Context) {
val guid = ysp?.getGuid()!! val guid = ysp?.getGuid()!!
val pid = tvModel.pid.value!! val pid = tvModel.pid.value!!
val sid = tvModel.sid.value!! val sid = tvModel.sid.value!!
yspBtraceService?.kvcollect( yspBtraceService.kvcollect(
c_timestamp = ysp?.generateGuid()!!, c_timestamp = ysp?.generateGuid()!!,
guid = guid, guid = guid,
c_guid = guid, c_guid = guid,
@@ -177,13 +229,12 @@ class Request(var context: Context) {
ftime = getDateFormat("yyyy-MM-dd HH:mm:ss"), ftime = getDateFormat("yyyy-MM-dd HH:mm:ss"),
seq = tvModel.seq.toString(), seq = tvModel.seq.toString(),
) )
?.enqueue(object : Callback<Void> { .enqueue(object : Callback<Void> {
override fun onResponse(call: Call<Void>, response: Response<Void>) { override fun onResponse(call: Call<Void>, response: Response<Void>) {
if (response.isSuccessful) { if (response.isSuccessful) {
// Log.d(TAG, "$title kvcollect success") // Log.d(TAG, "$title kvcollect success")
} else { } else {
Log.e(TAG, "$title kvcollect status error") Log.e(TAG, "$title kvcollect status error")
tvModel.firstSource()
} }
} }
@@ -195,7 +246,7 @@ class Request(var context: Context) {
} }
fun fetchPage() { fun fetchPage() {
yspProtoService?.getPage()?.enqueue(object : Callback<pageModel.Response> { yspProtoService.getPage().enqueue(object : Callback<pageModel.Response> {
override fun onResponse( override fun onResponse(
call: Call<pageModel.Response>, call: Call<pageModel.Response>,
response: Response<pageModel.Response> response: Response<pageModel.Response>
@@ -210,7 +261,7 @@ class Request(var context: Context) {
} }
Log.i( Log.i(
TAG, TAG,
"${item.channelName} ,${item.tvLogo},${item.pid},${item.streamId}" "${item.channelName},${item.pid},${item.streamId}"
) )
var channelType = "央视频道" var channelType = "央视频道"
if (item?.channelType === "weishi") { if (item?.channelType === "weishi") {
@@ -239,8 +290,8 @@ class Request(var context: Context) {
fun fetchProgram(tvViewModel: TVViewModel) { fun fetchProgram(tvViewModel: TVViewModel) {
val title = tvViewModel.title.value val title = tvViewModel.title.value
yspProtoService?.getProgram(tvViewModel.programId.value!!, getDateFormat("yyyyMMdd")) yspProtoService.getProgram(tvViewModel.programId.value!!, getDateFormat("yyyyMMdd"))
?.enqueue(object : Callback<epgProgramModel.Response> { .enqueue(object : Callback<epgProgramModel.Response> {
override fun onResponse( override fun onResponse(
call: Call<epgProgramModel.Response>, call: Call<epgProgramModel.Response>,
response: Response<epgProgramModel.Response> response: Response<epgProgramModel.Response>
@@ -25,8 +25,4 @@ data class TV(
", programId='" + programId + '\'' + ", programId='" + programId + '\'' +
'}' '}'
} }
companion object {
internal const val serialVersionUID = 727566175075960653L
}
} }
+37 -34
View File
@@ -7,6 +7,7 @@ object TVList {
private var mappingLogo = mapOf( private var mappingLogo = mapOf(
"CCTV4K 超高清" to "https://resources.yangshipin.cn/assets/oms/image/202306/3e9d06fd7244d950df5838750f1c6ac3456e172b51caca2c16d2282125b111e8.png?imageMogr2/format/webp", "CCTV4K 超高清" to "https://resources.yangshipin.cn/assets/oms/image/202306/3e9d06fd7244d950df5838750f1c6ac3456e172b51caca2c16d2282125b111e8.png?imageMogr2/format/webp",
"CCTV8K 超高清" to "https://static.wikia.nocookie.net/logos/images/6/69/CCTV8K.png/revision/latest/scale-to-width-down/120?cb=20230104110835&path-prefix=vi",
"CCTV1 综合" to "https://resources.yangshipin.cn/assets/oms/image/202306/d57905b93540bd15f0c48230dbbbff7ee0d645ff539e38866e2d15c8b9f7dfcd.png?imageMogr2/format/webp", "CCTV1 综合" to "https://resources.yangshipin.cn/assets/oms/image/202306/d57905b93540bd15f0c48230dbbbff7ee0d645ff539e38866e2d15c8b9f7dfcd.png?imageMogr2/format/webp",
"CCTV2 财经" to "https://resources.yangshipin.cn/assets/oms/image/202306/20115388de0207131af17eac86c33049b95d69eaff064e55653a1b941810a006.png?imageMogr2/format/webp", "CCTV2 财经" to "https://resources.yangshipin.cn/assets/oms/image/202306/20115388de0207131af17eac86c33049b95d69eaff064e55653a1b941810a006.png?imageMogr2/format/webp",
"CCTV3 综艺" to "https://resources.yangshipin.cn/assets/oms/image/202306/7b7a65c712450da3deb6ca66fbacf4f9aee00d3f20bd80eafb5ada01ec63eb3a.png?imageMogr2/format/webp", "CCTV3 综艺" to "https://resources.yangshipin.cn/assets/oms/image/202306/7b7a65c712450da3deb6ca66fbacf4f9aee00d3f20bd80eafb5ada01ec63eb3a.png?imageMogr2/format/webp",
@@ -31,10 +32,10 @@ object TVList {
"CGTN 阿拉伯语频道" to "https://resources.yangshipin.cn/assets/oms/image/202306/2e44e2aa3e7a1cedf07fd0ae59fe69e86a60a2632660a006e3e9e7397b2d107e.png?imageMogr2/format/webp", "CGTN 阿拉伯语频道" to "https://resources.yangshipin.cn/assets/oms/image/202306/2e44e2aa3e7a1cedf07fd0ae59fe69e86a60a2632660a006e3e9e7397b2d107e.png?imageMogr2/format/webp",
"CGTN 西班牙语频道" to "https://resources.yangshipin.cn/assets/oms/image/202309/7c337e3dbe64402ec7e4678a619a4a6d95144e42f35161181ff78e143b7cf67a.png?imageMogr2/format/webp", "CGTN 西班牙语频道" to "https://resources.yangshipin.cn/assets/oms/image/202309/7c337e3dbe64402ec7e4678a619a4a6d95144e42f35161181ff78e143b7cf67a.png?imageMogr2/format/webp",
"CGTN 纪录频道" to "https://resources.yangshipin.cn/assets/oms/image/202309/74d3ac436a7e374879578de1d87a941fbf566d39d5632b027c5097891ed32bd5.png?imageMogr2/format/webp", "CGTN 纪录频道" to "https://resources.yangshipin.cn/assets/oms/image/202309/74d3ac436a7e374879578de1d87a941fbf566d39d5632b027c5097891ed32bd5.png?imageMogr2/format/webp",
"风云剧场" to "https://resources.yangshipin.cn/assets/oms/image/202306/4d549e53e6d0f632d5a633d1945280797b153e588f919221a07faa869812cc89.png?imageMogr2/format/webp", "风云剧场" to "https://resources.yangshipin.cn/assets/oms/image/202306/4d549e53e6d0f632d5a633d1945280797b153e588f919221a07faa869812cc89.png?imageMogr2/format/webp",
"第一剧场" to "https://resources.yangshipin.cn/assets/oms/image/202306/a556bd7d93ce65e18f243a8892b5604f4faa994a4897315914216a710a706208.png?imageMogr2/format/webp", "第一剧场" to "https://resources.yangshipin.cn/assets/oms/image/202306/a556bd7d93ce65e18f243a8892b5604f4faa994a4897315914216a710a706208.png?imageMogr2/format/webp",
"怀旧剧场" to "https://resources.yangshipin.cn/assets/oms/image/202306/5661bd04fecdb6e899f801147a22ab5d3a475bf2b62e30aec2c0023190ebc9b1.png?imageMogr2/format/webp", "怀旧剧场" to "https://resources.yangshipin.cn/assets/oms/image/202306/5661bd04fecdb6e899f801147a22ab5d3a475bf2b62e30aec2c0023190ebc9b1.png?imageMogr2/format/webp",
"世界地理" to "https://resources.yangshipin.cn/assets/oms/image/202306/bb3c6c9e145d698137f5bb64a582021a01b51344b929003630eb769ea65832a9.png?imageMogr2/format/webp",
"风云音乐" to "https://resources.yangshipin.cn/assets/oms/image/202306/bbf1d024c5228b8dd128b0e3cb1717d173fab4ee84c3a4c8a57b1a215362ca3b.png?imageMogr2/format/webp", "风云音乐" to "https://resources.yangshipin.cn/assets/oms/image/202306/bbf1d024c5228b8dd128b0e3cb1717d173fab4ee84c3a4c8a57b1a215362ca3b.png?imageMogr2/format/webp",
"兵器科技" to "https://resources.yangshipin.cn/assets/oms/image/202306/4c6b6a6d3839889f34d33db3c2f80233b26b74d3489b393487635f8704e70796.png?imageMogr2/format/webp", "兵器科技" to "https://resources.yangshipin.cn/assets/oms/image/202306/4c6b6a6d3839889f34d33db3c2f80233b26b74d3489b393487635f8704e70796.png?imageMogr2/format/webp",
"风云足球" to "https://resources.yangshipin.cn/assets/oms/image/202306/cd1e2bb52b06a991de168733e5ff0f1d85adc8042d40c8f393f723543e5dd08a.png?imageMogr2/format/webp", "风云足球" to "https://resources.yangshipin.cn/assets/oms/image/202306/cd1e2bb52b06a991de168733e5ff0f1d85adc8042d40c8f393f723543e5dd08a.png?imageMogr2/format/webp",
@@ -44,7 +45,6 @@ object TVList {
"央视台球" to "https://resources.yangshipin.cn/assets/oms/image/202306/10e14a92478011aa6c3c8562e62127f3b1908e29fcd78e4b2b24b9e6d3ec2fbc.png?imageMogr2/format/webp", "央视台球" to "https://resources.yangshipin.cn/assets/oms/image/202306/10e14a92478011aa6c3c8562e62127f3b1908e29fcd78e4b2b24b9e6d3ec2fbc.png?imageMogr2/format/webp",
"电视指南" to "https://resources.yangshipin.cn/assets/oms/image/202306/244d72c0eb1615ed7d51c2f5db5a67f306aa3f58c05bc2d34de3aa7e956dc8c9.png?imageMogr2/format/webp", "电视指南" to "https://resources.yangshipin.cn/assets/oms/image/202306/244d72c0eb1615ed7d51c2f5db5a67f306aa3f58c05bc2d34de3aa7e956dc8c9.png?imageMogr2/format/webp",
"卫生健康" to "https://resources.yangshipin.cn/assets/oms/image/202306/54a6863656fdfd8f803be193ddf22441c5000a108833889816fd2d8911715ce8.png?imageMogr2/format/webp", "卫生健康" to "https://resources.yangshipin.cn/assets/oms/image/202306/54a6863656fdfd8f803be193ddf22441c5000a108833889816fd2d8911715ce8.png?imageMogr2/format/webp",
"东方卫视" to "https://resources.yangshipin.cn/assets/oms/image/202306/9bd372ca292a82ce3aa08772b07efc4af1f85c21d1f268ea33440c49e9a0a488.png?imageMogr2/format/webp", "东方卫视" to "https://resources.yangshipin.cn/assets/oms/image/202306/9bd372ca292a82ce3aa08772b07efc4af1f85c21d1f268ea33440c49e9a0a488.png?imageMogr2/format/webp",
"湖南卫视" to "https://resources.yangshipin.cn/assets/oms/image/202306/4120e89d3079d08aa17d382f69a2308ec70839b278367763c34a34666c75cb88.png?imageMogr2/format/webp", "湖南卫视" to "https://resources.yangshipin.cn/assets/oms/image/202306/4120e89d3079d08aa17d382f69a2308ec70839b278367763c34a34666c75cb88.png?imageMogr2/format/webp",
"湖北卫视" to "https://resources.yangshipin.cn/assets/oms/image/202306/7a6be5a2bb1dc53a945c016ff1f525dc4a84c51db371c15c89aa55404b0ba784.png?imageMogr2/format/webp", "湖北卫视" to "https://resources.yangshipin.cn/assets/oms/image/202306/7a6be5a2bb1dc53a945c016ff1f525dc4a84c51db371c15c89aa55404b0ba784.png?imageMogr2/format/webp",
@@ -69,6 +69,7 @@ object TVList {
) )
private var mappingEPG = mapOf( private var mappingEPG = mapOf(
"CCTV4K 超高清" to "600002264", "CCTV4K 超高清" to "600002264",
"CCTV8K 超高清" to "600156816",
"CCTV1 综合" to "600001859", "CCTV1 综合" to "600001859",
"CCTV2 财经" to "600001800", "CCTV2 财经" to "600001800",
"CCTV3 综艺" to "600001801", "CCTV3 综艺" to "600001801",
@@ -93,10 +94,10 @@ object TVList {
"CGTN 阿拉伯语频道" to "600084782", "CGTN 阿拉伯语频道" to "600084782",
"CGTN 西班牙语频道" to "600084744", "CGTN 西班牙语频道" to "600084744",
"CGTN 记录频道" to "600084781", "CGTN 记录频道" to "600084781",
"风云剧场" to "600099658", "风云剧场" to "600099658",
"第一剧场" to "600099655", "第一剧场" to "600099655",
"怀旧剧场" to "600099620", "怀旧剧场" to "600099620",
"世界地理" to "600099637",
"风云音乐" to "600099660", "风云音乐" to "600099660",
"兵器科技" to "600099649", "兵器科技" to "600099649",
"风云足球" to "600099636", "风云足球" to "600099636",
@@ -106,7 +107,6 @@ object TVList {
"央视台球" to "600099652", "央视台球" to "600099652",
"电视指南" to "600099656", "电视指南" to "600099656",
"卫生健康" to "600099651", "卫生健康" to "600099651",
"东方卫视" to "600002483", "东方卫视" to "600002483",
"湖南卫视" to "600002475", "湖南卫视" to "600002475",
"湖北卫视" to "600002508", "湖北卫视" to "600002508",
@@ -131,20 +131,21 @@ object TVList {
) )
private var mappingVideo = mapOf( private var mappingVideo = mapOf(
"CCTV4K 超高清" to arrayOf("600002264", "2000266303"), "CCTV4K 超高清" to arrayOf("600002264", "2000266303"),
"CCTV8K 超高清" to arrayOf("600156816", "2020603421"),
"CCTV1 综合" to arrayOf("600001859", "2000210103"), "CCTV1 综合" to arrayOf("600001859", "2000210103"),
"CCTV2 财经" to arrayOf("600001800", "2000203603"), "CCTV2 财经" to arrayOf("600001800", "2000203603"),
// "CCTV3 综艺" to arrayOf("600001801",""), "CCTV3 综艺" to arrayOf("600001801", "2000203803"),
"CCTV4 中文国际" to arrayOf("600001814", "2000204803"), "CCTV4 中文国际" to arrayOf("600001814", "2000204803"),
"CCTV5 体育" to arrayOf("600001818", "2000205103"), "CCTV5 体育" to arrayOf("600001818", "2000205103"),
"CCTV5+ 体育赛事" to arrayOf("600001817", "2000204503"), "CCTV5+ 体育赛事" to arrayOf("600001817", "2000204503"),
// "CCTV6 电影" to arrayOf("600001802",""), "CCTV6 电影" to arrayOf("600001802", "2000203303"),
"CCTV7 国防军事" to arrayOf("600004092", "2000510003"), "CCTV7 国防军事" to arrayOf("600004092", "2000510003"),
// "CCTV8 电视剧" to arrayOf("600001803",""), "CCTV8 电视剧" to arrayOf("600001803", "2000203903"),
"CCTV9 记录" to arrayOf("600004078", "2000499403"), "CCTV9 记录" to arrayOf("600004078", "2000499403"),
"CCTV10 科教" to arrayOf("600001805", "2000203503"), "CCTV10 科教" to arrayOf("600001805", "2000203503"),
"CCTV11 戏曲" to arrayOf("600001806", "2000204103"), "CCTV11 戏曲" to arrayOf("600001806", "2000204103"),
"CCTV12 社会与法" to arrayOf("600001807", "2000202603"), "CCTV12 社会与法" to arrayOf("600001807", "2000202603"),
// "CCTV13 新闻" to arrayOf("600001811",""), // "CCTV13 新闻" to arrayOf("600001811","2000204603"),
"CCTV14 少儿" to arrayOf("600001809", "2000204403"), "CCTV14 少儿" to arrayOf("600001809", "2000204403"),
"CCTV15 音乐" to arrayOf("600001815", "2000205003"), "CCTV15 音乐" to arrayOf("600001815", "2000205003"),
"CCTV16 奥林匹克" to arrayOf("600098637", "2012375003"), "CCTV16 奥林匹克" to arrayOf("600098637", "2012375003"),
@@ -155,20 +156,19 @@ object TVList {
"CGTN 阿拉伯语频道" to arrayOf("600084782", "2010155203"), "CGTN 阿拉伯语频道" to arrayOf("600084782", "2010155203"),
"CGTN 西班牙语频道" to arrayOf("600084744", "2010152503"), "CGTN 西班牙语频道" to arrayOf("600084744", "2010152503"),
"CGTN 记录频道" to arrayOf("600084781", "2010155403"), "CGTN 记录频道" to arrayOf("600084781", "2010155403"),
"风云剧场" to arrayOf("600099658", "2012513603"),
// "风云剧场" to arrayOf("600099658",""), "第一剧场" to arrayOf("600099655", "2012514403"),
// "第一剧场" to arrayOf("600099655",""), "怀旧剧场" to arrayOf("600099620", "2012511203"),
// "怀旧剧场" to arrayOf("600099620",""), "世界地理" to arrayOf("600099637", "2012513303"),
// "风云音乐" to arrayOf("600099660",""), "风云音乐" to arrayOf("600099660", "2012514103"),
// "兵器科技" to arrayOf("600099649",""), "兵器科技" to arrayOf("600099649", "2012513403"),
// "风云足球" to arrayOf("600099636",""), "风云足球" to arrayOf("600099636", "2012514203"),
// "高尔夫网球" to arrayOf("600099659",""), "高尔夫网球" to arrayOf("600099659", "2012512503"),
// "女性时尚" to arrayOf("600099650",""), "女性时尚" to arrayOf("600099650", "2012513903"),
// "央视文化精品" to arrayOf("600099653",""), "央视文化精品" to arrayOf("600099653", "2012513803"),
// "央视台球" to arrayOf("600099652",""), "央视台球" to arrayOf("600099652", "2012513703"),
// "电视指南" to arrayOf("600099656",""), "电视指南" to arrayOf("600099656", "2012514003"),
// "卫生健康" to arrayOf("600099651",""), "卫生健康" to arrayOf("600099651", "2012513503"),
"东方卫视" to arrayOf("600002483", "2000292403"), "东方卫视" to arrayOf("600002483", "2000292403"),
"湖南卫视" to arrayOf("600002475", "2000296203"), "湖南卫视" to arrayOf("600002475", "2000296203"),
"湖北卫视" to arrayOf("600002508", "2000294503"), "湖北卫视" to arrayOf("600002508", "2000294503"),
@@ -197,6 +197,7 @@ object TVList {
val tvs = """ val tvs = """
央视频道 央视频道
CCTV4K 超高清, CCTV4K 超高清,
CCTV8K 超高清,
CCTV1 综合,http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226231/index.m3u8 CCTV1 综合,http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226231/index.m3u8
CCTV2 财经,http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226195/index.m3u8 CCTV2 财经,http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226195/index.m3u8
CCTV3 综艺,http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226397/index.m3u8 CCTV3 综艺,http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226397/index.m3u8
@@ -215,24 +216,19 @@ CCTV14 少儿,http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226193/inde
CCTV15 音乐,http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225785/index.m3u8 CCTV15 音乐,http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225785/index.m3u8
CCTV16 奥林匹克,http://39.134.24.162/dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226921/index.m3u8;http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226921/index.m3u8 CCTV16 奥林匹克,http://39.134.24.162/dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226921/index.m3u8;http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226921/index.m3u8
CCTV17 农业农村,http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226198/index.m3u8 CCTV17 农业农村,http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226198/index.m3u8
CGTN,http://live.cgtn.com/1000/prog_index.m3u8
CGTN 法语频道,https://livefr.cgtn.com/1000f/prog_index.m3u8
CGTN 俄语频道,http://liveru.cgtn.com/1000r/prog_index.m3u8
CGTN 阿拉伯语频道,http://livear.cgtn.com/1000a/prog_index.m3u8
CGTN 西班牙语频道,http://livees.cgtn.com/500e/prog_index.m3u8;http://livees.cgtn.com/1000e/prog_index.m3u8
CGTN 纪录频道,https://livedoc.cgtn.com/500d/prog_index.m3u8
电视指南,http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226987/index.m3u8
风云足球,http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226984/index.m3u8
风云剧场,http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226950/index.m3u8 风云剧场,http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226950/index.m3u8
风云音乐,http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226953/index.m3u8
央视台球,http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226956/index.m3u8
第一剧场,http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226959/index.m3u8 第一剧场,http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226959/index.m3u8
女性时尚,http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226969/index.m3u8
怀旧剧场,http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226972/index.m3u8 怀旧剧场,http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226972/index.m3u8
世界地理,
风云音乐,http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226953/index.m3u8
兵器科技,http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226975/index.m3u8 兵器科技,http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226975/index.m3u8
风云足球,http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226984/index.m3u8
高尔夫网球,http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226978/index.m3u8 高尔夫网球,http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226978/index.m3u8
女性时尚,http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226969/index.m3u8
央视文化精品,http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226981/index.m3u8 央视文化精品,http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226981/index.m3u8
央视台球,http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226956/index.m3u8
电视指南,http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226987/index.m3u8
卫生健康,
地方频道 地方频道
东方卫视,http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226217/index.m3u8 东方卫视,http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226217/index.m3u8
湖南卫视,http://ottrrs.hl.chinamobile.com/PLTV/88888888/224/3221226307/index.m3u8;http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226211/index.m3u8 湖南卫视,http://ottrrs.hl.chinamobile.com/PLTV/88888888/224/3221226307/index.m3u8;http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226211/index.m3u8
@@ -255,6 +251,13 @@ CGTN 纪录频道,https://livedoc.cgtn.com/500d/prog_index.m3u8
四川卫视,http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225768/index.m3u8;http://39.134.24.166/dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225768/index.m3u8 四川卫视,http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225768/index.m3u8;http://39.134.24.166/dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225768/index.m3u8
东南卫视,http://ottrrs.hl.chinamobile.com/PLTV/88888888/224/3221226341/index.m3u8;http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225766/index.m3u8 东南卫视,http://ottrrs.hl.chinamobile.com/PLTV/88888888/224/3221226341/index.m3u8;http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225766/index.m3u8
海南卫视,http://ottrrs.hl.chinamobile.com/PLTV/88888888/224/3221226465/index.m3u8;http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225769/index.m3u8 海南卫视,http://ottrrs.hl.chinamobile.com/PLTV/88888888/224/3221226465/index.m3u8;http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225769/index.m3u8
国际频道
CGTN,http://live.cgtn.com/1000/prog_index.m3u8
CGTN 法语频道,https://livefr.cgtn.com/1000f/prog_index.m3u8
CGTN 俄语频道,http://liveru.cgtn.com/1000r/prog_index.m3u8
CGTN 阿拉伯语频道,http://livear.cgtn.com/1000a/prog_index.m3u8
CGTN 西班牙语频道,http://livees.cgtn.com/500e/prog_index.m3u8;http://livees.cgtn.com/1000e/prog_index.m3u8
CGTN 纪录频道,https://livedoc.cgtn.com/500d/prog_index.m3u8
""".trimIndent() """.trimIndent()
val map: MutableMap<String, MutableList<TV>> = mutableMapOf() val map: MutableMap<String, MutableList<TV>> = mutableMapOf()
@@ -1,17 +1,51 @@
package com.lizongying.mytv.api package com.lizongying.mytv.api
import okhttp3.OkHttpClient
import retrofit2.Retrofit import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.converter.protobuf.ProtoConverterFactory
class ApiClient { class ApiClient {
private val yspUrl = "https://player-api.yangshipin.cn/" private val yspUrl = "https://player-api.yangshipin.cn/"
private val myUrl = "https://lyrics.run/"
private val protoUrl = "https://capi.yangshipin.cn/"
private val traceUrl = "https://btrace.yangshipin.cn/"
private var okHttpClient = OkHttpClient.Builder()
.dns(DnsCache())
.build()
val yspApiService: YSPApiService by lazy { val yspApiService: YSPApiService by lazy {
Retrofit.Builder() Retrofit.Builder()
.baseUrl(yspUrl) .baseUrl(yspUrl)
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create()) .addConverterFactory(GsonConverterFactory.create())
.build().create(YSPApiService::class.java) .build().create(YSPApiService::class.java)
} }
val yspTokenService: YSPTokenService by lazy {
Retrofit.Builder()
.baseUrl(myUrl)
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.build().create(YSPTokenService::class.java)
}
val yspProtoService: YSPProtoService by lazy {
Retrofit.Builder()
.baseUrl(protoUrl)
.client(okHttpClient)
.addConverterFactory(ProtoConverterFactory.create())
.build().create(YSPProtoService::class.java)
}
val yspBtraceService: YSPBtraceService by lazy {
Retrofit.Builder()
.baseUrl(traceUrl)
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.build().create(YSPBtraceService::class.java)
}
} }
@@ -1,17 +0,0 @@
package com.lizongying.mytv.api
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
class BtraceClient {
private val yspUrl = "https://btrace.yangshipin.cn/"
val yspBtraceService: YSPBtraceService by lazy {
Retrofit.Builder()
.baseUrl(yspUrl)
.addConverterFactory(GsonConverterFactory.create())
.build().create(YSPBtraceService::class.java)
}
}
@@ -0,0 +1,23 @@
package com.lizongying.mytv.api
import okhttp3.Dns
import java.net.InetAddress
import java.util.concurrent.ConcurrentHashMap
class DnsCache : Dns {
private val dnsCache: MutableMap<String, List<InetAddress>> = ConcurrentHashMap()
override fun lookup(hostname: String): List<InetAddress> {
dnsCache[hostname]?.let {
return it
}
val addresses = InetAddress.getAllByName(hostname).toList()
if (addresses.isNotEmpty()) {
dnsCache[hostname] = addresses
}
return addresses
}
}
@@ -0,0 +1,11 @@
package com.lizongying.mytv.api
data class Info(
val code: Int?,
val msg: String?,
val data: InfoData,
)
data class InfoData(
val token: String,
)
@@ -15,6 +15,7 @@ data class LiveInfo(
data class LiveInfoData( data class LiveInfoData(
val chanll: String, val chanll: String,
val playurl: String, val playurl: String,
val errinfo: String,
) )
data class LiveInfoRequest( data class LiveInfoRequest(
@@ -1,16 +0,0 @@
package com.lizongying.mytv.api
import retrofit2.Retrofit
import retrofit2.converter.protobuf.ProtoConverterFactory
class ProtoClient {
private val protoUrl = "https://capi.yangshipin.cn/"
val yspProtoService: YSPProtoService by lazy {
Retrofit.Builder()
.baseUrl(protoUrl)
.addConverterFactory(ProtoConverterFactory.create())
.build().create(YSPProtoService::class.java)
}
}
@@ -70,6 +70,8 @@ class YSP(var context: Context) {
defn = "fhd" defn = "fhd"
randStr = getRand() randStr = getRand()
guid = newGuid()
timeStr = getTimeStr() timeStr = getTimeStr()
// guid = "lq3oqitm_1e15dnzgjnb" // guid = "lq3oqitm_1e15dnzgjnb"
@@ -105,6 +107,15 @@ class YSP(var context: Context) {
return guid return guid
} }
fun newGuid(): String {
guid = generateGuid()
with(sharedPref!!.edit()) {
putString("guid", guid)
apply()
}
return guid
}
fun getRand(): String { fun getRand(): String {
var n = "" var n = ""
val e = "ABCDEFGHIJKlMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" val e = "ABCDEFGHIJKlMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
@@ -13,20 +13,9 @@ interface YSPApiService {
"content-type: application/json;charset=UTF-8", "content-type: application/json;charset=UTF-8",
"referer: https://www.yangshipin.cn/", "referer: https://www.yangshipin.cn/",
"yspappid: 519748109", "yspappid: 519748109",
"cookie: guid=1; vplatform=109"
) )
fun getLiveInfo( fun getLiveInfo(
@Body request: LiveInfoRequest, @Header("cookie") cookie: String,
): Call<LiveInfo>
@POST("v1/player/get_live_info")
@Headers(
"content-type: application/json;charset=UTF-8",
"referer: https://www.yangshipin.cn/",
"yspappid: 519748109",
"cookie: guid=1; vplatform=109; yspopenid=vu0-8lgGV2LW9QjDeuBFsX8yMnzs37Q3_HZF6XyVDpGR_I; vusession=mTIVXnDeVUg0FcP6Xo4kaXd9fxlc70a558kySW4phQU"
)
fun getLiveInfo2(
@Body request: LiveInfoRequest, @Body request: LiveInfoRequest,
): Call<LiveInfo> ): Call<LiveInfo>
} }
@@ -0,0 +1,11 @@
package com.lizongying.mytv.api
import retrofit2.Call
import retrofit2.http.GET
interface YSPTokenService {
@GET("my-tv/v1/info")
fun getInfo(
): Call<Info>
}
@@ -19,8 +19,14 @@ class TVViewModel(private var tv: TV) : ViewModel() {
private var rowPosition: Int = 0 private var rowPosition: Int = 0
private var itemPosition: Int = 0 private var itemPosition: Int = 0
var retryTimes: Int = 0
var retryMaxTimes: Int = 5
var programUpdateTime: Long = 0 var programUpdateTime: Long = 0
private val _errInfo = MutableLiveData<String>()
val errInfo: LiveData<String>
get() = _errInfo
private val _programId = MutableLiveData<String>() private val _programId = MutableLiveData<String>()
val programId: LiveData<String> val programId: LiveData<String>
get() = _programId get() = _programId
@@ -65,10 +71,31 @@ class TVViewModel(private var tv: TV) : ViewModel() {
val ready: LiveData<Boolean> val ready: LiveData<Boolean>
get() = _ready get() = _ready
private var mMinimumLoadableRetryCount = 3 private var mMinimumLoadableRetryCount = 5
var seq = 0 var seq = 0
var needToken = false
private val channelsNeedToken = arrayOf(
"CCTV3 综艺",
"CCTV6 电影",
"CCTV8 电视剧",
"风云剧场",
"第一剧场",
"怀旧剧场",
"世界地理",
"风云音乐",
"兵器科技",
"风云足球",
"高尔夫网球",
"女性时尚",
"央视文化精品",
"央视台球",
"电视指南",
"卫生健康",
)
fun addVideoUrl(url: String) { fun addVideoUrl(url: String) {
if (_videoUrl.value?.isNotEmpty() == true) { if (_videoUrl.value?.isNotEmpty() == true) {
if (_videoUrl.value!!.last().contains("cctv.cn")) { if (_videoUrl.value!!.last().contains("cctv.cn")) {
@@ -119,6 +146,10 @@ class TVViewModel(private var tv: TV) : ViewModel() {
_pid.value = tv.pid _pid.value = tv.pid
_sid.value = tv.sid _sid.value = tv.sid
_program.value = mutableListOf() _program.value = mutableListOf()
if (tv.title in channelsNeedToken) {
needToken = true
}
} }
fun getRowPosition(): Int { fun getRowPosition(): Int {
@@ -137,6 +168,10 @@ class TVViewModel(private var tv: TV) : ViewModel() {
itemPosition = position itemPosition = position
} }
fun setErrInfo(info: String) {
_errInfo.value = info
}
fun update(t: TV) { fun update(t: TV) {
tv = t tv = t
} }
Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

-1
View File
@@ -2,7 +2,6 @@
<style name="CustomImageCardViewStyle" parent="Widget.Leanback.ImageCardViewStyle"> <style name="CustomImageCardViewStyle" parent="Widget.Leanback.ImageCardViewStyle">
<!-- <item name="infoVisibility">activated</item>-->
<item name="lbImageCardViewType">Title|Content</item> <item name="lbImageCardViewType">Title|Content</item>
</style> </style>