Compare commits

..
26 Commits
Author SHA1 Message Date
Li ZongYing 10f261be8b fix save state 2024-02-21 21:57:05 +08:00
Li ZongYing 52d356817a fix some keys invalid 2024-02-21 19:26:11 +08:00
Li ZongYing 6ede7f76ef auto auth 2024-02-21 16:36:37 +08:00
Li ZongYing a4da01adf4 new memu style 2024-02-21 15:14:06 +08:00
Li ZongYing 8b33c7c94c optimize memu 2024-02-20 20:55:35 +08:00
Li ZongYing 84a6c0f78e menu delay disappears 2024-02-20 11:33:30 +08:00
Li ZongYing 1417bbf57b auto-startup 2024-02-19 15:57:39 +08:00
Li ZongYing ce678b8741 test release api 2024-02-11 10:14:23 +08:00
Li ZongYing 353dc0570f fix ysp 2024-02-09 22:36:48 +08:00
Li ZongYing d7a60531ab fix cctv6 2024-02-08 00:22:24 +08:00
Li ZongYing 764f2a1549 fix time error 2024-02-07 19:21:17 +08:00
Li ZongYing aa4d52681f fix ysp 2024-02-07 03:05:11 +08:00
Li ZongYing 8137515605 fix ysp err 2024-02-05 06:25:31 +08:00
Li ZongYing 6c16408b90 upgrade player 2024-02-04 22:23:28 +08:00
Li ZongYing 44ab3a6669 fix channel number did not disappear 2024-02-03 23:30:37 +08:00
Li ZongYing 917b245bbe readme 2024-02-02 23:34:39 +08:00
Li ZongYing dd4550cf4f replay on resume 2024-02-01 18:10:58 +08:00
Li ZongYing 4bdc625718 add channel 2024-01-26 18:30:31 +08:00
Li ZongYing cda19995b2 optimize channel switch 2024-01-25 15:12:47 +08:00
Li ZongYing 1eb2f257b5 change channel order 2024-01-25 11:04:06 +08:00
Li ZongYing 9feb0dc4bc channel num setting 2024-01-19 12:18:17 +08:00
Li ZongYing 46311036d6 number selection 2024-01-17 16:27:25 +08:00
Li ZongYing 1aade3a48d 17ok 2024-01-14 18:58:37 +08:00
Li ZongYing 2528cf33db test 17 2024-01-14 10:09:59 +08:00
Li ZongYing 4364f66ec5 17 2024-01-14 02:53:09 +08:00
Li ZongYing 49cd7b3af2 help page 2024-01-11 16:32:08 +08:00
34 changed files with 788 additions and 1082 deletions
+2 -2
View File
@@ -19,8 +19,8 @@ body:
label: my-ty 版本 label: my-ty 版本
description: 请选择正在使用的版本 description: 请选择正在使用的版本
options: options:
- 通用版 - 最新稳定版
- 专用版 - 最新 CI 版
validations: validations:
required: true required: true
- type: textarea - type: textarea
+1 -1
View File
@@ -11,7 +11,7 @@ body:
options: options:
- label: 之前没有人提交过类似或相同的功能请求。 - label: 之前没有人提交过类似或相同的功能请求。
required: true required: true
- label: 这个建议不会背离 my-tv 的初衷。 - label: 这个建议不会背离 LibChecker 的初衷。
required: true required: true
- type: textarea - type: textarea
id: propose id: propose
+5 -21
View File
@@ -14,29 +14,10 @@
## 更新日志 ## 更新日志
### v1.6.4(通用)
* 增加CETV1
* 增加凤凰卫视
* 默认关闭开机启动
### v1.6.3(安卓5及以上专用)
* 增加CETV1
* 凤凰卫视增强画质
* 默认关闭开机启动
* 延迟菜单自动关闭时间
* 解决一些可能导致首次打开时黑屏的问题
### v1.6.2(通用) ### v1.6.2(通用)
* 修复按键无效的问题
* 新的频道列表样式 * 新的频道列表样式
### v1.6.1(安卓5及以上专用)
* 增加凤凰卫视
### v1.6.0(通用) ### v1.6.0(通用)
* 通用(春晚緊急修復) * 通用(春晚緊急修復)
@@ -213,15 +194,18 @@ adb install my-tv.apk
## TODO ## TODO
* 音量不同 * 音量不同
* 大湾区卫视、广东4k超高清、广东珠江、三沙卫视 * 大湾区卫视、广东4k超高清、广东珠江
* CETV教育频道
* CHC高清三个电影频道 * CHC高清三个电影频道
* 地方频道 * 地方频道
* 收藏夹 * 收藏夹
* 自定义源 * 自定义源
* 凤凰卫视、凤凰资讯台
* 海外 * 海外
* 1.5.0 无法安装,1.5.1 可以安装
* 选中的图标比例能否相差更大
* 节目增加预告 * 节目增加预告
* 频道列表优化 * 频道列表优化
* 自动更新
## 赞赏 ## 赞赏
+1 -1
View File
@@ -101,7 +101,7 @@ dependencies {
implementation "androidx.media3:media3-exoplayer-hls:$media3_version" implementation "androidx.media3:media3-exoplayer-hls:$media3_version"
// 21:2.9.0 17:2.6.4 // 21:2.9.0 17:2.6.4
def retrofit2_version = "2.9.0" def retrofit2_version = "2.6.4"
implementation 'com.google.protobuf:protobuf-kotlin:3.25.1' implementation 'com.google.protobuf:protobuf-kotlin:3.25.1'
implementation "com.squareup.retrofit2:converter-gson:$retrofit2_version" implementation "com.squareup.retrofit2:converter-gson:$retrofit2_version"
-4
View File
@@ -38,9 +38,5 @@
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
</intent-filter> </intent-filter>
</receiver> </receiver>
<provider
android:name=".InitializerProvider"
android:authorities="${applicationId}.InitializerProvider"
android:exported="false"/>
</application> </application>
</manifest> </manifest>
Binary file not shown.
Binary file not shown.
@@ -7,7 +7,8 @@ import android.content.Intent
class BootReceiver : BroadcastReceiver() { class BootReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) { override fun onReceive(context: Context, intent: Intent) {
if (SP.bootStartup) { val sp = context.getSharedPreferences("MainActivity", Context.MODE_PRIVATE)
if (sp.getBoolean(MainActivity.BOOT_STARTUP, true)) {
context.startActivity( context.startActivity(
Intent(context, MainActivity::class.java) Intent(context, MainActivity::class.java)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
@@ -0,0 +1,149 @@
package com.lizongying.mytv
import android.graphics.Color
import android.view.ContextThemeWrapper
import android.view.KeyEvent
import android.view.View
import android.view.ViewGroup
import android.view.animation.ScaleAnimation
import android.widget.ImageView
import androidx.leanback.widget.ImageCardView
import androidx.lifecycle.LifecycleOwner
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.lizongying.mytv.models.TVListViewModel
import com.lizongying.mytv.models.TVViewModel
class CardAdapter(
private val recyclerView: RecyclerView,
private val owner: LifecycleOwner,
private var tvListViewModel: TVListViewModel,
) :
RecyclerView.Adapter<CardAdapter.ViewHolder>() {
private var listener: ItemListener? = null
private var focused: View? = null
private var defaultFocused = false
var defaultFocus: Int = -1
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val cardView = object :
ImageCardView(ContextThemeWrapper(parent.context, R.style.CustomImageCardTheme)) {}
cardView.isFocusable = true
cardView.isFocusableInTouchMode = true
return ViewHolder(cardView)
}
fun clear() {
focused?.clearFocus()
recyclerView.invalidate()
}
private fun startScaleAnimation(view: View, fromScale: Float, toScale: Float, duration: Long) {
val scaleAnimation = ScaleAnimation(
fromScale, toScale,
fromScale, toScale,
ScaleAnimation.RELATIVE_TO_SELF, 0.5f,
ScaleAnimation.RELATIVE_TO_SELF, 0.5f
)
scaleAnimation.duration = duration
scaleAnimation.fillAfter = false
view.startAnimation(scaleAnimation)
}
override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
val item = tvListViewModel.getTVViewModel(position)
val tvViewModel = item as TVViewModel
val cardView = viewHolder.view as ImageCardView
if (!defaultFocused && item.id.value == defaultFocus) {
cardView.requestFocus()
defaultFocused = true
}
val onFocusChangeListener = View.OnFocusChangeListener { _, hasFocus ->
listener?.onItemFocusChange(item, hasFocus)
// if (hasFocus && defaultFocus == item.id.value) {
if (hasFocus) {
focused = cardView
startScaleAnimation(cardView, 0.9f, 1.0f, 200)
}
}
cardView.onFocusChangeListener = onFocusChangeListener
cardView.setOnClickListener { _ ->
listener?.onItemClicked(item)
}
cardView.setOnKeyListener { _, keyCode, event: KeyEvent? ->
if (event?.action == KeyEvent.ACTION_DOWN) {
return@setOnKeyListener listener?.onKey(keyCode) ?: false
}
false
}
cardView.titleText = tvViewModel.title.value
when (tvViewModel.title.value) {
"CCTV8K 超高清" -> Glide.with(viewHolder.view.context)
.load(R.drawable.cctv8k)
.centerInside()
.into(cardView.mainImageView)
"天津卫视" -> Glide.with(viewHolder.view.context)
.load(R.drawable.tianjin)
.centerInside()
.into(cardView.mainImageView)
"新疆卫视" -> Glide.with(viewHolder.view.context)
.load(R.drawable.xinjiang)
.centerInside()
.into(cardView.mainImageView)
"兵团卫视" -> Glide.with(viewHolder.view.context)
.load(R.drawable.bingtuan)
.centerInside()
.into(cardView.mainImageView)
else -> Glide.with(viewHolder.view.context)
.load(tvViewModel.logo.value)
.centerInside()
.into(cardView.mainImageView)
}
cardView.mainImageView.setBackgroundColor(Color.WHITE)
cardView.setMainImageScaleType(ImageView.ScaleType.CENTER_INSIDE)
tvViewModel.program.observe(owner) { _ ->
val program = tvViewModel.getProgramOne()
if (program != null) {
cardView.contentText = program.name
}
}
}
override fun getItemCount() = tvListViewModel.size()
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val view = itemView
}
interface ItemListener {
fun onItemFocusChange(tvViewModel: TVViewModel, hasFocus: Boolean)
fun onItemClicked(tvViewModel: TVViewModel)
fun onKey(keyCode: Int): Boolean
}
fun setItemListener(listener: ItemListener) {
this.listener = listener
}
companion object {
private const val TAG = "CardAdapter"
}
}
@@ -1,82 +0,0 @@
package com.lizongying.mytv
import android.graphics.Color
import android.view.ContextThemeWrapper
import android.view.ViewGroup
import android.widget.ImageView
import androidx.leanback.widget.ImageCardView
import androidx.leanback.widget.Presenter
import androidx.lifecycle.LifecycleOwner
import com.bumptech.glide.Glide
import com.lizongying.mytv.models.TVViewModel
class CardPresenter(
private val owner: LifecycleOwner,
) : Presenter() {
override fun onCreateViewHolder(parent: ViewGroup): ViewHolder {
val cardView = object :
ImageCardView(ContextThemeWrapper(parent.context, R.style.CustomImageCardTheme)) {}
cardView.isFocusable = true
cardView.isFocusableInTouchMode = true
return ViewHolder(cardView)
}
override fun onBindViewHolder(viewHolder: ViewHolder, item: Any) {
val tvViewModel = item as TVViewModel
val cardView = viewHolder.view as ImageCardView
cardView.titleText = tvViewModel.title.value
cardView.setMainImageDimensions(CARD_WIDTH, CARD_HEIGHT)
cardView.tag = tvViewModel.videoUrl.value
when (tvViewModel.title.value) {
"CCTV8K 超高清" -> Glide.with(viewHolder.view.context)
.load(R.drawable.cctv8k)
.centerInside()
.into(cardView.mainImageView)
"天津卫视" -> Glide.with(viewHolder.view.context)
.load(R.drawable.tianjin)
.centerInside()
.into(cardView.mainImageView)
"新疆卫视" -> Glide.with(viewHolder.view.context)
.load(R.drawable.xinjiang)
.centerInside()
.into(cardView.mainImageView)
"兵团卫视" -> Glide.with(viewHolder.view.context)
.load(R.drawable.bingtuan)
.centerInside()
.into(cardView.mainImageView)
else -> Glide.with(viewHolder.view.context)
.load(tvViewModel.logo.value)
.centerInside()
.into(cardView.mainImageView)
}
cardView.setBackgroundColor(Color.WHITE)
cardView.setMainImageScaleType(ImageView.ScaleType.CENTER_INSIDE)
tvViewModel.program.observe(owner) { _ ->
val program = tvViewModel.getProgramOne()
if (program != null) {
cardView.contentText = program.name
}
}
}
override fun onUnbindViewHolder(viewHolder: ViewHolder) {
val cardView = viewHolder.view as ImageCardView
cardView.mainImage = null
}
companion object {
private const val TAG = "CardPresenter"
private const val CARD_WIDTH = 300
private const val CARD_HEIGHT = 101
}
}
@@ -1,157 +0,0 @@
package com.lizongying.mytv
import android.content.Context
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.io.File
/**
*@author LeGend
*@date 2024/2/4 22:42
*/
object ChannelUtils {
/**
* 获取服务器channel版本
*
* @param context Context
*
* @return 服务器channel版本
*/
suspend fun getServerVersion(context: Context): Int {
return withContext(Dispatchers.IO) {
val client = okhttp3.OkHttpClient.Builder().connectTimeout(500, java.util.concurrent.TimeUnit.MILLISECONDS)
.readTimeout(1, java.util.concurrent.TimeUnit.SECONDS).build()
client.newCall(okhttp3.Request.Builder().url(getServerVersionUrl(context)).build()).execute()
.use { response ->
if (!response.isSuccessful) throw java.io.IOException("Unexpected code $response")
val body = response.body()
body?.string()?.toInt() ?: 0
}
}
}
/**
* 获取服务器channel
*
* @param url String 服务器地址
*
* @return Array<TV> 服务器channel
*
* @throws java.io.IOException 网络请求失败
*/
suspend fun getServerChannel(url: String): List<TV> {
val result = withContext(Dispatchers.IO) {
val client = okhttp3.OkHttpClient.Builder().connectTimeout(500, java.util.concurrent.TimeUnit.MILLISECONDS)
.readTimeout(1, java.util.concurrent.TimeUnit.SECONDS).build()
val request = okhttp3.Request.Builder().url(url).build()
client.newCall(request).execute().use { response ->
if (!response.isSuccessful) throw java.io.IOException("Unexpected code $response")
val body = response.body()
body?.string() ?: ""
}
}
return withContext(Dispatchers.Default) {
val type = object : com.google.gson.reflect.TypeToken<List<TV>>() {}.type
com.google.gson.Gson().fromJson(result, type)
}
}
/**
* 获取服务器地址
*
* @param context Context
*
* @return 服务器地址
*/
fun getServerUrl(context: Context): String {
return context.resources.getString(R.string.server_url)
}
/**
* 获取serverVersion的URL
*
* @param context Context
*
* @return serverVersionURL 服务器版本地址
*/
suspend fun getServerVersionUrl(context: Context): String {
return withContext(Dispatchers.IO) {
context.resources.getString(R.string.server_version_url)
}
}
/**
* 获取本地channel版本
*
* @param context Context
*
* @return 本地channel
*/
suspend fun getLocalVersion(context: Context): Int {
return withContext(Dispatchers.IO) {
val file = File(getAppDirectory(context), "channels")
//检查本地是否已经有保存的channels.json,若无保存的Channel.json则从读取assert中文件
val savedVersion =
context.getSharedPreferences("saved_version", Context.MODE_PRIVATE).getInt("version", Integer.MIN_VALUE)
if (!file.exists() || savedVersion == Integer.MIN_VALUE) {
context.resources.getInteger(R.integer.local_channel_version)
} else {
savedVersion
}
}
}
/**
* 获取本地可读取的目录
* @param context Context
*
* @return 可读取的目录
*/
private fun getAppDirectory(context: Context): File {
return context.filesDir
}
/**
* 获取本地channel
*
* @param context Context
*
* @return Array<TV> 本地channel
*/
suspend fun getLocalChannel(context: Context): List<TV> {
val str = withContext(Dispatchers.IO) {
if (File(getAppDirectory(context), "channels").exists()) {
File(getAppDirectory(context), "channels").readText()
} else {
context.resources.openRawResource(R.raw.channels).bufferedReader().use { it.readText() }
}
}
return withContext(Dispatchers.Default) {
val type = object : com.google.gson.reflect.TypeToken<List<TV>>() {}.type
com.google.gson.Gson().fromJson(str, type)
}
}
/**
* 更新channels.json
*
* @param context Context
*
* @return 无
*
* @throws java.io.IOException 写入失败
*/
suspend fun updateLocalChannel(context: Context, version: Int, channels: List<TV>) {
withContext(Dispatchers.IO) {
val file = File(getAppDirectory(context), "channels")
if (!file.exists()) {
file.createNewFile()
}
file.writeText(com.google.gson.Gson().toJson(channels))
context.getSharedPreferences("saved_version", Context.MODE_PRIVATE).edit().putInt(
"version", version
).apply()
}
}
}
@@ -0,0 +1,48 @@
package com.lizongying.mytv
import android.content.Context
import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.Rect
import android.view.View
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView
class GrayOverlayItemDecoration(private val context: Context) : RecyclerView.ItemDecoration() {
private val grayOverlayPaint = Paint().apply {
color = ContextCompat.getColor(context, R.color.gray_overlay)
style = Paint.Style.FILL
}
override fun onDrawOver(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
super.onDrawOver(c, parent, state)
val childCount = parent.childCount
for (i in 0 until childCount) {
val child = parent.getChildAt(i)
if (!child.hasFocus()) {
// 计算遮罩层的大小
val overlayRect = Rect(
child.left,
child.top,
child.right,
child.bottom
)
// 绘制灰色遮罩层
c.drawRect(overlayRect, grayOverlayPaint)
}
}
}
override fun getItemOffsets(
outRect: Rect,
view: View,
parent: RecyclerView,
state: RecyclerView.State
) {
super.getItemOffsets(outRect, view, parent, state)
// 在此处设置偏移量为0,以防止遮罩层影响项的布局
outRect.setEmpty()
}
}
@@ -47,10 +47,6 @@ class InfoFragment : Fragment() {
.load(R.drawable.bingtuan) .load(R.drawable.bingtuan)
.into(binding.infoLogo) .into(binding.infoLogo)
"CETV1" -> Glide.with(this)
.load(R.drawable.cetv1)
.into(binding.infoLogo)
else -> Glide.with(this) else -> Glide.with(this)
.load(tvViewModel.logo.value) .load(tvViewModel.logo.value)
.into(binding.infoLogo) .into(binding.infoLogo)
@@ -1,39 +0,0 @@
package com.lizongying.mytv
import android.content.ContentProvider
import android.content.ContentValues
import android.net.Uri
internal class InitializerProvider : ContentProvider() {
// Happens before Application#onCreate.It's fine to init something here
override fun onCreate(): Boolean {
SP.init(context!!)
return true
}
override fun query(
uri: Uri,
projection: Array<out String>?,
selection: String?,
selectionArgs: Array<out String>?,
sortOrder: String?,
) = unsupported()
override fun getType(uri: Uri) = unsupported()
override fun insert(uri: Uri, values: ContentValues?) = unsupported()
override fun delete(uri: Uri, selection: String?, selectionArgs: Array<out String>?) =
unsupported()
override fun update(
uri: Uri,
values: ContentValues?,
selection: String?,
selectionArgs: Array<out String>?,
) = unsupported()
private fun unsupported(errorMessage: String? = null): Nothing =
throw UnsupportedOperationException(errorMessage)
}
@@ -1,5 +1,7 @@
package com.lizongying.mytv package com.lizongying.mytv
import android.content.Context
import android.content.SharedPreferences
import android.content.pm.PackageInfo import android.content.pm.PackageInfo
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.content.pm.Signature import android.content.pm.Signature
@@ -25,7 +27,7 @@ import kotlinx.coroutines.launch
import java.security.MessageDigest import java.security.MessageDigest
class MainActivity : FragmentActivity(), Request.RequestListener { class MainActivity : FragmentActivity() {
private var ready = 0 private var ready = 0
private var playerFragment = PlayerFragment() private var playerFragment = PlayerFragment()
@@ -39,27 +41,29 @@ class MainActivity : FragmentActivity(), Request.RequestListener {
private lateinit var gestureDetector: GestureDetector private lateinit var gestureDetector: GestureDetector
private val handler = Handler() private val handler = Handler()
private val delayHideMain: Long = 10000 private val delayHideMain: Long = 5000
private val delayHideSetting: Long = 10000 private val delayHideSetting: Long = 10000
// init { lateinit var sharedPref: SharedPreferences
// lifecycleScope.launch(Dispatchers.IO) { private var channelReversal = false
// val utilsJob = async(start = CoroutineStart.LAZY) { Utils.init() } private var channelNum = true
// private var bootStartup = true
// utilsJob.start()
// init {
// utilsJob.await() lifecycleScope.launch(Dispatchers.IO) {
// } val utilsJob = async(start = CoroutineStart.LAZY) { Utils.init() }
// }
utilsJob.start()
utilsJob.await()
}
}
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
Log.i(TAG, "onCreate") Log.i(TAG, "onCreate")
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main) setContentView(R.layout.activity_main)
Request.onCreate()
Request.setRequestListener(this)
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN) window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
window.decorView.systemUiVisibility = SYSTEM_UI_FLAG_HIDE_NAVIGATION window.decorView.systemUiVisibility = SYSTEM_UI_FLAG_HIDE_NAVIGATION
@@ -74,6 +78,12 @@ class MainActivity : FragmentActivity(), Request.RequestListener {
.commit() .commit()
} }
gestureDetector = GestureDetector(this, GestureListener()) gestureDetector = GestureDetector(this, GestureListener())
sharedPref = getPreferences(Context.MODE_PRIVATE)
channelReversal = sharedPref.getBoolean(CHANNEL_REVERSAL, channelReversal)
channelNum = sharedPref.getBoolean(CHANNEL_NUM, channelNum)
bootStartup = sharedPref.getBoolean(BOOT_STARTUP, bootStartup)
val packageInfo = getPackageInfo() val packageInfo = getPackageInfo()
val versionName = packageInfo.versionName val versionName = packageInfo.versionName
val versionCode = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { val versionCode = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
@@ -81,18 +91,13 @@ class MainActivity : FragmentActivity(), Request.RequestListener {
} else { } else {
packageInfo.versionCode.toLong() packageInfo.versionCode.toLong()
} }
settingFragment = SettingFragment( settingFragment =
versionName, SettingFragment(versionName, versionCode, channelReversal, channelNum, bootStartup)
versionCode,
SP.channelReversal,
SP.channelNum,
SP.bootStartup
)
} }
fun showInfoFragment(tvViewModel: TVViewModel) { fun showInfoFragment(tvViewModel: TVViewModel) {
infoFragment.show(tvViewModel) infoFragment.show(tvViewModel)
if (SP.channelNum) { if (channelNum) {
channelFragment.show(tvViewModel) channelFragment.show(tvViewModel)
} }
} }
@@ -106,7 +111,7 @@ class MainActivity : FragmentActivity(), Request.RequestListener {
return return
} }
if (SP.channelNum) { if (channelNum) {
channelFragment.show(channel) channelFragment.show(channel)
} }
} }
@@ -140,6 +145,7 @@ class MainActivity : FragmentActivity(), Request.RequestListener {
val transaction = supportFragmentManager.beginTransaction() val transaction = supportFragmentManager.beginTransaction()
if (mainFragment.isHidden) { if (mainFragment.isHidden) {
mainFragment.setPosition()
transaction.show(mainFragment) transaction.show(mainFragment)
mainActive() mainActive()
} else { } else {
@@ -180,7 +186,7 @@ class MainActivity : FragmentActivity(), Request.RequestListener {
fun fragmentReady() { fun fragmentReady() {
ready++ ready++
Log.i(TAG, "ready $ready") Log.i(TAG, "ready $ready")
if (ready == 5) { if (ready == 4) {
mainFragment.fragmentReady() mainFragment.fragmentReady()
} }
} }
@@ -233,6 +239,30 @@ class MainActivity : FragmentActivity(), Request.RequestListener {
} }
} }
fun saveChannelReversal(channelReversal: Boolean) {
with(sharedPref.edit()) {
putBoolean(CHANNEL_REVERSAL, channelReversal)
apply()
}
this.channelReversal = channelReversal
}
fun saveChannelNum(channelNum: Boolean) {
with(sharedPref.edit()) {
putBoolean(CHANNEL_NUM, channelNum)
apply()
}
this.channelNum = channelNum
}
fun saveBootStartup(bootStartup: Boolean) {
with(sharedPref.edit()) {
putBoolean(BOOT_STARTUP, bootStartup)
apply()
}
this.bootStartup = bootStartup
}
private fun showSetting() { private fun showSetting() {
if (!mainFragment.isHidden) { if (!mainFragment.isHidden) {
return return
@@ -256,7 +286,7 @@ class MainActivity : FragmentActivity(), Request.RequestListener {
private fun channelUp() { private fun channelUp() {
if (mainFragment.isHidden) { if (mainFragment.isHidden) {
if (SP.channelReversal) { if (channelReversal) {
next() next()
return return
} }
@@ -273,7 +303,7 @@ class MainActivity : FragmentActivity(), Request.RequestListener {
private fun channelDown() { private fun channelDown() {
if (mainFragment.isHidden) { if (mainFragment.isHidden) {
if (SP.channelReversal) { if (channelReversal) {
prev() prev()
return return
} }
@@ -306,7 +336,9 @@ class MainActivity : FragmentActivity(), Request.RequestListener {
}, 2000) }, 2000)
} }
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
fun onKey(keyCode: Int): Boolean {
Log.i(TAG, "keyCode $keyCode")
when (keyCode) { when (keyCode) {
KeyEvent.KEYCODE_0 -> { KeyEvent.KEYCODE_0 -> {
showChannel("0") showChannel("0")
@@ -418,6 +450,7 @@ class MainActivity : FragmentActivity(), Request.RequestListener {
} }
KeyEvent.KEYCODE_DPAD_LEFT -> { KeyEvent.KEYCODE_DPAD_LEFT -> {
channelUp()
// if (mainFragment.isHidden) { // if (mainFragment.isHidden) {
// prevSource() // prevSource()
// } else { // } else {
@@ -431,6 +464,7 @@ class MainActivity : FragmentActivity(), Request.RequestListener {
} }
KeyEvent.KEYCODE_DPAD_RIGHT -> { KeyEvent.KEYCODE_DPAD_RIGHT -> {
channelDown()
// if (mainFragment.isHidden) { // if (mainFragment.isHidden) {
// nextSource() // nextSource()
// } else { // } else {
@@ -442,6 +476,13 @@ class MainActivity : FragmentActivity(), Request.RequestListener {
// } // }
} }
} }
return false
}
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
if (onKey(keyCode)) {
return true
}
return super.onKeyDown(keyCode, event) return super.onKeyDown(keyCode, event)
} }
@@ -516,17 +557,10 @@ class MainActivity : FragmentActivity(), Request.RequestListener {
handler.removeCallbacks(hideMain) handler.removeCallbacks(hideMain)
} }
override fun onDestroy() { companion object {
super.onDestroy() private const val TAG = "MainActivity"
Request.onDestroy() private const val CHANNEL_REVERSAL = "channel_reversal"
private const val CHANNEL_NUM = "channel_num"
const val BOOT_STARTUP = "boot_startup"
} }
override fun onRequestFinished() {
fragmentReady()
}
private companion object {
const val TAG = "MainActivity"
}
} }
@@ -1,225 +1,255 @@
package com.lizongying.mytv package com.lizongying.mytv
import android.content.SharedPreferences
import android.os.Bundle 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.KeyEvent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast import android.widget.Toast
import androidx.leanback.app.BrowseSupportFragment import androidx.fragment.app.Fragment
import androidx.leanback.widget.ArrayObjectAdapter
import androidx.leanback.widget.HeaderItem
import androidx.leanback.widget.ListRow
import androidx.leanback.widget.ListRowPresenter
import androidx.leanback.widget.ListRowPresenter.SelectItemViewHolderTask
import androidx.leanback.widget.OnItemViewClickedListener
import androidx.leanback.widget.OnItemViewSelectedListener
import androidx.leanback.widget.Presenter
import androidx.leanback.widget.Row
import androidx.leanback.widget.RowPresenter
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.lizongying.mytv.Utils.dpToPx
import com.lizongying.mytv.Utils.getDateTimestamp import com.lizongying.mytv.Utils.getDateTimestamp
import com.lizongying.mytv.api.YSP import com.lizongying.mytv.databinding.RowBinding
import com.lizongying.mytv.databinding.ShowBinding
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 kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
class MainFragment : BrowseSupportFragment() {
class MainFragment : Fragment(), CardAdapter.ItemListener {
private var itemPosition = 0 private var itemPosition = 0
private var rowsAdapter: ArrayObjectAdapter? = null private var rowList: MutableList<View> = mutableListOf()
private var _binding: ShowBinding? = null
private val binding get() = _binding!!
private var request = Request()
var tvListViewModel = TVListViewModel() var tvListViewModel = TVListViewModel()
private lateinit var sharedPref: SharedPreferences
private var lastVideoUrl = "" private var lastVideoUrl = ""
private val handler = Handler(Looper.getMainLooper()) private val handler = Handler(Looper.getMainLooper())
private lateinit var mUpdateProgramRunnable: UpdateProgramRunnable private lateinit var mUpdateProgramRunnable: UpdateProgramRunnable
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreateView(
Log.i(TAG, "onCreate") inflater: LayoutInflater, container: ViewGroup?,
super.onCreate(savedInstanceState) savedInstanceState: Bundle?
headersState = HEADERS_DISABLED ): View {
} _binding = ShowBinding.inflate(inflater, container, false)
return binding.root
override fun onStart() {
Log.i(TAG, "onStart")
super.onStart()
} }
override fun onActivityCreated(savedInstanceState: Bundle?) { override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState) super.onActivityCreated(savedInstanceState)
activity?.let { YSP.init(it) } activity?.let { request.initYSP(it) }
sharedPref = (activity as? MainActivity)?.sharedPref!!
loadRows() itemPosition = sharedPref.getInt(POSITION, 0)
setupEventListeners() view?.post {
val content = binding.content
mUpdateProgramRunnable = UpdateProgramRunnable() var idx: Long = 0
handler.post(mUpdateProgramRunnable) for ((k, v) in TVList.list) {
val itemBinding: RowBinding =
RowBinding.inflate(layoutInflater, content, false)
tvListViewModel.tvListViewModel.value?.forEach { tvViewModel -> val tvListViewModelCurrent = TVListViewModel()
tvViewModel.errInfo.observe(viewLifecycleOwner) { _ -> for ((idx2, v1) in v.withIndex()) {
if (tvViewModel.errInfo.value != null val tvViewModel = TVViewModel(v1)
&& tvViewModel.id.value == itemPosition tvViewModel.setRowPosition(idx.toInt())
) { tvViewModel.setItemPosition(idx2)
Toast.makeText(context, tvViewModel.errInfo.value, Toast.LENGTH_SHORT).show() tvListViewModelCurrent.addTVViewModel(tvViewModel)
tvListViewModel.addTVViewModel(tvViewModel)
}
tvListViewModel.maxNum.add(v.size)
val adapter =
CardAdapter(
itemBinding.rowItems,
viewLifecycleOwner,
tvListViewModelCurrent,
)
rowList.add(itemBinding.rowItems)
adapter.setItemListener(this)
itemBinding.rowHeader.text = k
itemBinding.rowItems.tag = idx.toInt()
itemBinding.rowItems.adapter = adapter
itemBinding.rowItems.layoutManager =
GridLayoutManager(context, 6)
itemBinding.rowItems.layoutParams.height =
dpToPx(92 * ((tvListViewModelCurrent.size() + 6 - 1) / 6))
itemBinding.rowItems.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
(activity as MainActivity).mainActive()
}
})
val itemDecoration = context?.let { GrayOverlayItemDecoration(it) }
if (itemDecoration != null) {
itemBinding.rowItems.addItemDecoration(itemDecoration)
}
val layoutParams = itemBinding.row.layoutParams as ViewGroup.MarginLayoutParams
layoutParams.topMargin = dpToPx(11F)
itemBinding.row.layoutParams = layoutParams
content.addView(itemBinding.row)
idx++
}
mUpdateProgramRunnable = UpdateProgramRunnable()
handler.post(mUpdateProgramRunnable)
if (itemPosition >= tvListViewModel.size()) {
itemPosition = 0
}
val tv = tvListViewModel.getTVViewModel(itemPosition)
for (i in rowList) {
if (i.tag as Int == tv?.getRowPosition()) {
((i as RecyclerView).adapter as CardAdapter).defaultFocus = itemPosition
break
} }
} }
tvViewModel.ready.observe(viewLifecycleOwner) { _ ->
// not first time && channel not change tvListViewModel.setItemPosition(itemPosition)
if (tvViewModel.ready.value != null tvListViewModel.tvListViewModel.value?.forEach { tvViewModel ->
&& tvViewModel.id.value == itemPosition tvViewModel.errInfo.observe(viewLifecycleOwner) { _ ->
&& check(tvViewModel) if (tvViewModel.errInfo.value != null
) { && tvViewModel.id.value == itemPosition
Log.i(TAG, "ready ${tvViewModel.title.value}") ) {
(activity as? MainActivity)?.play(tvViewModel) Toast.makeText(context, tvViewModel.errInfo.value, Toast.LENGTH_SHORT)
.show()
}
} }
} tvViewModel.ready.observe(viewLifecycleOwner) { _ ->
tvViewModel.change.observe(viewLifecycleOwner) { _ ->
if (tvViewModel.change.value != null) { // not first time && channel not change
val title = tvViewModel.title.value if (tvViewModel.ready.value != null
Log.i(TAG, "switch $title") && tvViewModel.id.value == itemPosition
if (tvViewModel.pid.value != "") { && check(tvViewModel)
Log.i(TAG, "request $title") ) {
lifecycleScope.launch(Dispatchers.IO) { Log.i(TAG, "ready ${tvViewModel.title.value}")
tvViewModel.let { Request.fetchData(it) } (activity as? MainActivity)?.play(tvViewModel)
} }
(activity as? MainActivity)?.showInfoFragment(tvViewModel) }
setSelectedPosition( tvViewModel.change.observe(viewLifecycleOwner) { _ ->
tvViewModel.getRowPosition(), true, if (tvViewModel.change.value != null) {
SelectItemViewHolderTask(tvViewModel.getItemPosition()) val title = tvViewModel.title.value
) Log.i(TAG, "switch $title")
} else { if (tvViewModel.pid.value != "") {
if (check(tvViewModel)) { Log.i(TAG, "request $title")
(activity as? MainActivity)?.play(tvViewModel) lifecycleScope.launch(Dispatchers.IO) {
tvViewModel.let { request.fetchData(it) }
}
(activity as? MainActivity)?.showInfoFragment(tvViewModel) (activity as? MainActivity)?.showInfoFragment(tvViewModel)
setSelectedPosition( setPosition(
tvViewModel.getRowPosition(), true, tvViewModel.getRowPosition(), tvViewModel.getItemPosition()
SelectItemViewHolderTask(tvViewModel.getItemPosition())
) )
} else {
if (check(tvViewModel)) {
(activity as? MainActivity)?.play(tvViewModel)
(activity as? MainActivity)?.showInfoFragment(tvViewModel)
setPosition(
tvViewModel.getRowPosition(), tvViewModel.getItemPosition()
)
}
} }
} }
} }
} }
(activity as MainActivity).fragmentReady()
} }
(activity as MainActivity).fragmentReady()
} }
fun toLastPosition() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
setSelectedPosition( super.onViewCreated(view, savedInstanceState)
selectedPosition, false,
SelectItemViewHolderTask(tvListViewModel.maxNum[selectedPosition] - 1)
)
} }
fun toFirstPosition() { override fun onKey(keyCode: Int): Boolean {
setSelectedPosition( if (this.isHidden) {
selectedPosition, false, when (keyCode) {
SelectItemViewHolderTask(0) KeyEvent.KEYCODE_DPAD_UP -> {
) (activity as MainActivity).onKey(keyCode)
} return true
}
override fun startHeadersTransition(withHeaders: Boolean) { KeyEvent.KEYCODE_DPAD_DOWN -> {
} (activity as MainActivity).onKey(keyCode)
return true
private fun loadRows() {
rowsAdapter = ArrayObjectAdapter(ListRowPresenter())
val cardPresenter = CardPresenter(viewLifecycleOwner)
var idx: Long = 0
for ((k, v) in TVList.list) {
val listRowAdapter = ArrayObjectAdapter(cardPresenter)
for ((idx2, v1) in v.withIndex()) {
val tvViewModel = TVViewModel(v1)
tvViewModel.setRowPosition(idx.toInt())
tvViewModel.setItemPosition(idx2)
tvListViewModel.addTVViewModel(tvViewModel)
listRowAdapter.add(tvViewModel)
}
tvListViewModel.maxNum.add(v.size)
val header = HeaderItem(idx, k)
rowsAdapter!!.add(ListRow(header, listRowAdapter))
idx++
}
adapter = rowsAdapter
itemPosition = SP.itemPosition
if (itemPosition >= tvListViewModel.size()) {
itemPosition = 0
}
tvListViewModel.setItemPosition(itemPosition)
}
fun prevSource() {
view?.post {
val tvViewModel = tvListViewModel.getTVViewModel(itemPosition)
if (tvViewModel != null) {
if (tvViewModel.videoUrl.value!!.size > 1) {
val videoIndex = tvViewModel.videoIndex.value?.minus(1)
if (videoIndex == -1) {
tvViewModel.setVideoIndex(tvViewModel.videoUrl.value!!.size - 1)
}
tvViewModel.changed()
} }
} }
} }
return false
} }
fun nextSource() { override fun onItemFocusChange(tvViewModel: TVViewModel, hasFocus: Boolean) {
view?.post { if (hasFocus) {
val tvViewModel = tvListViewModel.getTVViewModel(itemPosition) tvListViewModel.setItemPositionCurrent(tvViewModel.id.value!!)
if (tvViewModel != null) {
if (tvViewModel.videoUrl.value!!.size > 1) { val row = tvViewModel.getRowPosition()
val videoIndex = tvViewModel.videoIndex.value?.plus(1)
if (videoIndex == tvViewModel.videoUrl.value!!.size) { for (i in rowList) {
tvViewModel.setVideoIndex(0) if (i.tag as Int != row) {
} ((i as RecyclerView).adapter as CardAdapter).clear()
tvViewModel.changed()
} }
} }
(activity as MainActivity).mainActive()
} }
} }
private fun setupEventListeners() { override fun onItemClicked(tvViewModel: TVViewModel) {
onItemViewClickedListener = ItemViewClickedListener() Log.i(TAG, "onItemClicked")
onItemViewSelectedListener = ItemViewSelectedListener() if (this.isHidden) {
(activity as? MainActivity)?.switchMainFragment()
return
}
if (itemPosition != tvViewModel.id.value!!) {
itemPosition = tvViewModel.id.value!!
tvListViewModel.setItemPosition(itemPosition)
tvListViewModel.getTVViewModel(itemPosition)?.changed()
}
(activity as? MainActivity)?.switchMainFragment()
} }
private inner class ItemViewClickedListener : OnItemViewClickedListener { fun setPosition() {
override fun onItemClicked( val tvViewModel = tvListViewModel.getTVViewModel(itemPosition)
itemViewHolder: Presenter.ViewHolder, rowList[tvViewModel!!.getRowPosition()].post {
item: Any, ((rowList[tvViewModel.getRowPosition()] as RecyclerView).layoutManager as GridLayoutManager).findViewByPosition(
rowViewHolder: RowPresenter.ViewHolder, tvViewModel.getItemPosition()
row: Row )?.requestFocus()
) {
if (item is TVViewModel) {
if (itemPosition != item.id.value!!) {
itemPosition = item.id.value!!
tvListViewModel.setItemPosition(itemPosition)
tvListViewModel.getTVViewModel(itemPosition)?.changed()
}
(activity as? MainActivity)?.switchMainFragment()
}
} }
} }
private inner class ItemViewSelectedListener : OnItemViewSelectedListener { fun setPosition(rowPosition: Int, itemPosition: Int) {
override fun onItemSelected( rowList[rowPosition].post {
itemViewHolder: Presenter.ViewHolder?, item: Any?, ((rowList[rowPosition] as RecyclerView).layoutManager as GridLayoutManager).findViewByPosition(
rowViewHolder: RowPresenter.ViewHolder, row: Row itemPosition
) { )?.requestFocus()
if (item is TVViewModel) {
tvListViewModel.setItemPositionCurrent(item.id.value!!)
(activity as MainActivity).mainActive()
}
} }
((rowList[rowPosition] as RecyclerView).adapter as CardAdapter).defaultFocus = itemPosition
} }
fun check(tvViewModel: TVViewModel): Boolean { fun check(tvViewModel: TVViewModel): Boolean {
@@ -282,11 +312,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 (tvViewModel.program.value!!.last().et - timestamp < 600) { if (tvViewModel.program.value!!.last().et - timestamp < 600) {
tvViewModel.programUpdateTime = timestamp tvViewModel.programUpdateTime = timestamp
Request.fetchProgram(tvViewModel) request.fetchProgram(tvViewModel)
} }
} }
} }
@@ -312,8 +342,11 @@ class MainFragment : BrowseSupportFragment() {
override fun onStop() { override fun onStop() {
Log.i(TAG, "onStop") Log.i(TAG, "onStop")
super.onStop() super.onStop()
SP.itemPosition = itemPosition with(sharedPref.edit()) {
Log.i(TAG, "position saved") putInt(POSITION, itemPosition)
apply()
}
Log.i(TAG, "$POSITION $itemPosition saved")
} }
override fun onDestroy() { override fun onDestroy() {
@@ -324,7 +357,14 @@ class MainFragment : BrowseSupportFragment() {
} }
} }
override fun onDestroyView() {
Log.i(TAG, "onDestroyView")
super.onDestroyView()
_binding = null
}
companion object { companion object {
private const val TAG = "MainFragment" private const val TAG = "MainFragment"
private const val POSITION = "position"
} }
} }
+33 -184
View File
@@ -1,5 +1,6 @@
package com.lizongying.mytv package com.lizongying.mytv
import android.content.Context
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
import android.util.Base64 import android.util.Base64
@@ -8,13 +9,9 @@ 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
import com.lizongying.mytv.api.AuthRequest import com.lizongying.mytv.api.AuthRequest
import com.lizongying.mytv.api.FAuth
import com.lizongying.mytv.api.FAuthService
import com.lizongying.mytv.api.Info import com.lizongying.mytv.api.Info
import com.lizongying.mytv.api.InfoV2
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.Token
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
@@ -29,22 +26,19 @@ import retrofit2.Response
import javax.crypto.Cipher import javax.crypto.Cipher
import javax.crypto.spec.IvParameterSpec import javax.crypto.spec.IvParameterSpec
import javax.crypto.spec.SecretKeySpec import javax.crypto.spec.SecretKeySpec
import kotlin.math.max
object Request { class Request {
private const val TAG = "Request"
private var yspTokenService: YSPTokenService = ApiClient().yspTokenService private var yspTokenService: YSPTokenService = ApiClient().yspTokenService
private var yspApiService: YSPApiService = ApiClient().yspApiService private var yspApiService: YSPApiService = ApiClient().yspApiService
private var yspBtraceService: YSPBtraceService = ApiClient().yspBtraceService private var yspBtraceService: YSPBtraceService = ApiClient().yspBtraceService
private var yspProtoService: YSPProtoService = ApiClient().yspProtoService private var yspProtoService: YSPProtoService = ApiClient().yspProtoService
private var fAuthService: FAuthService = ApiClient().fAuthService private var ysp: YSP? = null
private var token = "" private var token = ""
private var tokenFH = ""
private var needAuth = false private var needAuth = false
// TODO onDestroy
private val handler = Handler(Looper.getMainLooper()) private val handler = Handler(Looper.getMainLooper())
private lateinit var btraceRunnable: BtraceRunnable private lateinit var btraceRunnable: BtraceRunnable
private var tokenRunnable: TokenRunnable = TokenRunnable() private var tokenRunnable: TokenRunnable = TokenRunnable()
@@ -53,16 +47,12 @@ object Request {
private val input = private val input =
"""{"mver":"1","subver":"1.2","host":"www.yangshipin.cn/#/tv/home?pid=","referer":"","canvas":"YSPANGLE(Apple,ANGLEMetalRenderer:AppleM1Pro,UnspecifiedVersion)"}""".toByteArray() """{"mver":"1","subver":"1.2","host":"www.yangshipin.cn/#/tv/home?pid=","referer":"","canvas":"YSPANGLE(Apple,ANGLEMetalRenderer:AppleM1Pro,UnspecifiedVersion)"}""".toByteArray()
private var listener: RequestListener? = null init {
handler.post(tokenRunnable)
fun onCreate() {
Log.i(TAG, "onCreate")
fetchInfoV2()
} }
fun onDestroy() { fun initYSP(context: Context) {
Log.i(TAG, "onDestroy") ysp = YSP(context)
handler.removeCallbacks(tokenRunnable)
} }
var call: Call<LiveInfo>? = null var call: Call<LiveInfo>? = null
@@ -73,9 +63,9 @@ object Request {
val title = tvModel.title.value val title = tvModel.title.value
val data = YSP.getAuthData(tvModel) val data = ysp?.getAuthData(tvModel)
val request = AuthRequest(data) val request = data?.let { AuthRequest(it) }
callAuth = request.let { yspApiService.getAuth("guid=${YSP.getGuid()}; $cookie", it) } callAuth = request?.let { yspApiService.getAuth("guid=${ysp?.getGuid()}; $cookie", it) }
callAuth?.enqueue(object : Callback<Auth> { callAuth?.enqueue(object : Callback<Auth> {
override fun onResponse(call: Call<Auth>, response: Response<Auth>) { override fun onResponse(call: Call<Auth>, response: Response<Auth>) {
@@ -84,7 +74,7 @@ object Request {
if (liveInfo?.data?.token != null) { if (liveInfo?.data?.token != null) {
Log.i(TAG, "token ${liveInfo.data.token}") Log.i(TAG, "token ${liveInfo.data.token}")
YSP.token = liveInfo.data.token ysp?.token = liveInfo.data.token
fetchVideo(tvModel, cookie) fetchVideo(tvModel, cookie)
} else { } else {
Log.e(TAG, "$title token error") Log.e(TAG, "$title token error")
@@ -154,12 +144,12 @@ object Request {
val title = tvModel.title.value val title = tvModel.title.value
tvModel.seq = 0 tvModel.seq = 0
val data = YSP.switch(tvModel) val data = ysp?.switch(tvModel)
val request = LiveInfoRequest(data) val request = data?.let { LiveInfoRequest(it) }
call = request.let { call = request?.let {
yspApiService.getLiveInfo( yspApiService.getLiveInfo(
"guid=${YSP.getGuid()}; $cookie", "guid=${ysp?.getGuid()}; $cookie",
YSP.token, ysp!!.token,
it it
) )
} }
@@ -330,7 +320,6 @@ object Request {
} }
fun fetchVideo(tvModel: TVViewModel) { fun fetchVideo(tvModel: TVViewModel) {
Log.d(TAG, "fetchVideo")
if (token == "") { if (token == "") {
yspTokenService.getInfo("") yspTokenService.getInfo("")
.enqueue(object : Callback<Info> { .enqueue(object : Callback<Info> {
@@ -339,7 +328,7 @@ object Request {
token = response.body()?.data?.token!! token = response.body()?.data?.token!!
Log.i(TAG, "info success $token") Log.i(TAG, "info success $token")
val cookie = val cookie =
"versionName=99.99.99; versionCode=999999; vplatform=109; platformVersion=Chrome; deviceModel=120; appid=1400421205; yspappid=519748109; yspopenid=vu0-8lgGV2LW9QjDeuBFsX8yMnzs37Q3_HZF6XyVDpGR_I; vusession=$token" "versionName=99.99.99; versionCode=999999; vplatform=109; platformVersion=Chrome; deviceModel=120; appid=1400421205; yspappid=519748109;yspopenid=vu0-8lgGV2LW9QjDeuBFsX8yMnzs37Q3_HZF6XyVDpGR_I; vusession=$token"
fetchVideo(tvModel, cookie) fetchVideo(tvModel, cookie)
} else { } else {
Log.e(TAG, "info status error") Log.e(TAG, "info status error")
@@ -372,59 +361,12 @@ object Request {
}) })
} else { } else {
val cookie = val cookie =
"versionName=99.99.99; versionCode=999999; vplatform=109; platformVersion=Chrome; deviceModel=120; appid=1400421205; yspappid=519748109; yspopenid=vu0-8lgGV2LW9QjDeuBFsX8yMnzs37Q3_HZF6XyVDpGR_I; vusession=$token" "versionName=99.99.99; versionCode=999999; vplatform=109; platformVersion=Chrome; deviceModel=120; appid=1400421205; yspappid=519748109;yspopenid=vu0-8lgGV2LW9QjDeuBFsX8yMnzs37Q3_HZF6XyVDpGR_I; vusession=$token"
fetchVideo(tvModel, cookie) fetchVideo(tvModel, cookie)
} }
} }
private var fAuth: Call<FAuth>? = null
fun fetchFAuth(tvModel: TVViewModel) {
call?.cancel()
callAuth?.cancel()
fAuth?.cancel()
val title = tvModel.title.value
var qa = "HD"
if (tokenFH != "") {
qa = "FHD"
}
fAuth = fAuthService.getAuth(tokenFH, tvModel.getTV().pid, qa)
fAuth?.enqueue(object : Callback<FAuth> {
override fun onResponse(call: Call<FAuth>, response: Response<FAuth>) {
if (response.isSuccessful && response.body()?.data?.live_url != null) {
val url = response.body()?.data?.live_url!!
// Log.d(TAG, "$title url $url")
tvModel.addVideoUrl(url)
tvModel.allReady()
tvModel.retryTimes = 0
} else {
Log.e(TAG, "auth status error")
if (tvModel.tokenRetryTimes < tvModel.tokenRetryMaxTimes) {
tvModel.tokenRetryTimes++
fetchFAuth(tvModel)
}
}
}
override fun onFailure(call: Call<FAuth>, t: Throwable) {
Log.e(TAG, "auth request error $t")
if (tvModel.tokenRetryTimes < tvModel.tokenRetryMaxTimes) {
tvModel.tokenRetryTimes++
fetchFAuth(tvModel)
}
}
})
}
fun fetchData(tvModel: TVViewModel) { fun fetchData(tvModel: TVViewModel) {
Log.d(TAG, "fetchData")
if (tvModel.getTV().channel == "港澳台") {
fetchFAuth(tvModel)
return
}
if (tvModel.getTV().needToken) { if (tvModel.getTV().needToken) {
if (needAuth) { if (needAuth) {
fetchAuth(tvModel) fetchAuth(tvModel)
@@ -442,121 +384,32 @@ object Request {
} }
} }
class TokenRunnable : Runnable { inner class TokenRunnable : Runnable {
override fun run() { override fun run() {
fetchToken() fetchToken()
handler.postDelayed(this, 600000)
} }
} }
private fun fetchInfoV2() {
yspTokenService.getInfoV2()
.enqueue(object : Callback<InfoV2> {
override fun onResponse(call: Call<InfoV2>, response: Response<InfoV2>) {
if (response.isSuccessful) {
val t = response.body()?.t
val f = response.body()?.f
val e = response.body()?.e
val c = response.body()?.c
if (!t.isNullOrEmpty()) {
token = t
Log.i(TAG, "token success $token")
if (e != null) {
handler.postDelayed(
tokenRunnable,
max(600000, (e - 1500) * 1000).toLong()
)
} else {
Log.e(TAG, "e empty")
handler.postDelayed(
tokenRunnable,
600000
)
}
} else {
Log.e(TAG, "token empty")
handler.postDelayed(
tokenRunnable,
600000
)
}
if (!f.isNullOrEmpty()) {
tokenFH = f
Log.i(TAG, "tokenFH success $tokenFH")
}
if (c != null) {
Utils.setBetween(c * 1000L)
Log.i(TAG, "current time $c")
}
} else {
Log.e(TAG, "token status error")
handler.postDelayed(
tokenRunnable,
600000
)
}
listener?.onRequestFinished()
}
override fun onFailure(call: Call<InfoV2>, t: Throwable) {
Log.e(TAG, "token request error $t")
handler.postDelayed(
tokenRunnable,
600000
)
listener?.onRequestFinished()
}
})
}
fun fetchToken() { fun fetchToken() {
yspTokenService.getToken(token) yspTokenService.getInfo(token)
.enqueue(object : Callback<Token> { .enqueue(object : Callback<Info> {
override fun onResponse(call: Call<Token>, response: Response<Token>) { override fun onResponse(call: Call<Info>, response: Response<Info>) {
if (response.isSuccessful) { if (response.isSuccessful) {
val t = response.body()?.t token = response.body()?.data?.token!!
val e = response.body()?.e Log.i(TAG, "info success $token")
if (!t.isNullOrEmpty()) {
token = t
Log.e(TAG, "token success $token")
if (e != null) {
handler.postDelayed(
tokenRunnable,
max(600000, (e - 1500) * 1000).toLong()
)
} else {
Log.e(TAG, "e empty")
handler.postDelayed(
tokenRunnable,
600000
)
}
} else {
Log.e(TAG, "token empty")
handler.postDelayed(
tokenRunnable,
600000
)
}
} else { } else {
Log.e(TAG, "token status error") Log.e(TAG, "token status error")
handler.postDelayed(
tokenRunnable,
600000
)
} }
} }
override fun onFailure(call: Call<Token>, t: Throwable) { override fun onFailure(call: Call<Info>, t: Throwable) {
Log.e(TAG, "token request error $t") Log.e(TAG, "token request error $t")
handler.postDelayed(
tokenRunnable,
600000
)
} }
}) })
} }
class BtraceRunnable(private val tvModel: TVViewModel) : Runnable { inner class BtraceRunnable(private val tvModel: TVViewModel) : Runnable {
override fun run() { override fun run() {
fetchBtrace(tvModel) fetchBtrace(tvModel)
handler.postDelayed(this, 60000) handler.postDelayed(this, 60000)
@@ -566,11 +419,11 @@ object Request {
fun fetchBtrace(tvModel: TVViewModel) { fun fetchBtrace(tvModel: TVViewModel) {
val title = tvModel.title.value val title = tvModel.title.value
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,
prog = sid, prog = sid,
@@ -578,7 +431,7 @@ object Request {
fpid = pid, fpid = pid,
livepid = pid, livepid = pid,
sUrl = "https://www.yangshipin.cn/#/tv/home?pid=$pid", sUrl = "https://www.yangshipin.cn/#/tv/home?pid=$pid",
playno = YSP.getRand(), playno = ysp?.getRand()!!,
ftime = getDateFormat("yyyy-MM-dd HH:mm:ss"), ftime = getDateFormat("yyyy-MM-dd HH:mm:ss"),
seq = tvModel.seq.toString(), seq = tvModel.seq.toString(),
) )
@@ -670,11 +523,7 @@ object Request {
} }
} }
interface RequestListener { companion object {
fun onRequestFinished() private const val TAG = "Request"
}
fun setRequestListener(listener: RequestListener) {
this.listener = listener
} }
} }
@@ -1,48 +0,0 @@
package com.lizongying.mytv
import android.content.Context
import android.content.SharedPreferences
object SP {
// Name of the sp file TODO Should use a meaningful name and do migrations
private const val SP_FILE_NAME = "MainActivity"
// If Change channel with up and down in reversed order or not
private const val KEY_CHANNEL_REVERSAL = "channel_reversal"
// If use channel num to select channel or not
private const val KEY_CHANNEL_NUM = "channel_num"
// If start app on device boot or not
private const val KEY_BOOT_STARTUP = "boot_startup"
// Position in list of the selected channel item
private const val KEY_POSITION = "position"
// guid
private const val KEY_GUID = "guid"
private lateinit var sp: SharedPreferences
/**
* The method must be invoked as early as possible(At least before using the keys)
*/
fun init(context: Context) {
sp = context.getSharedPreferences(SP_FILE_NAME, Context.MODE_PRIVATE)
}
var channelReversal: Boolean
get() = sp.getBoolean(KEY_CHANNEL_REVERSAL, false)
set(value) = sp.edit().putBoolean(KEY_CHANNEL_REVERSAL, value).apply()
var channelNum: Boolean
get() = sp.getBoolean(KEY_CHANNEL_NUM, true)
set(value) = sp.edit().putBoolean(KEY_CHANNEL_NUM, value).apply()
var bootStartup: Boolean
get() = sp.getBoolean(KEY_BOOT_STARTUP, false)
set(value) = sp.edit().putBoolean(KEY_BOOT_STARTUP, value).apply()
var itemPosition: Int
get() = sp.getInt(KEY_POSITION, 0)
set(value) = sp.edit().putInt(KEY_POSITION, value).apply()
var guid: String
get() = sp.getString(KEY_GUID, "") ?: ""
set(value) = sp.edit().putString(KEY_GUID, value).apply()
}
@@ -39,21 +39,21 @@ class SettingFragment(
val switchChannelReversal = _binding?.switchChannelReversal val switchChannelReversal = _binding?.switchChannelReversal
switchChannelReversal?.isChecked = channelReversal switchChannelReversal?.isChecked = channelReversal
switchChannelReversal?.setOnCheckedChangeListener { _, isChecked -> switchChannelReversal?.setOnCheckedChangeListener { _, isChecked ->
SP.channelReversal = isChecked (activity as MainActivity).saveChannelReversal(isChecked)
(activity as MainActivity).settingActive() (activity as MainActivity).settingActive()
} }
val switchChannelNum = _binding?.switchChannelNum val switchChannelNum = _binding?.switchChannelNum
switchChannelNum?.isChecked = channelNum switchChannelNum?.isChecked = channelNum
switchChannelNum?.setOnCheckedChangeListener { _, isChecked -> switchChannelNum?.setOnCheckedChangeListener { _, isChecked ->
SP.channelNum = isChecked (activity as MainActivity).saveChannelNum(isChecked)
(activity as MainActivity).settingActive() (activity as MainActivity).settingActive()
} }
val switchBootStartup = _binding?.switchBootStartup val switchBootStartup = _binding?.switchBootStartup
switchBootStartup?.isChecked = bootStartup switchBootStartup?.isChecked = bootStartup
switchBootStartup?.setOnCheckedChangeListener { _, isChecked -> switchBootStartup?.setOnCheckedChangeListener { _, isChecked ->
SP.bootStartup = isChecked (activity as MainActivity).saveBootStartup(isChecked)
(activity as MainActivity).settingActive() (activity as MainActivity).settingActive()
} }
+72 -196
View File
@@ -1,22 +1,15 @@
package com.lizongying.mytv package com.lizongying.mytv
import android.content.Context
import android.util.Log
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.io.IOException
object TVList { object TVList {
var list = mapOf( var list = mapOf(
"央视" to listOf( "央视频道" to listOf(
TV( TV(
0, 0,
"CCTV1 综合", "CCTV1 综合",
"CCTV1", "CCTV1",
listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226231/index.m3u8"), listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226231/index.m3u8"),
0, 0,
"央视", "央视频道",
"https://resources.yangshipin.cn/assets/oms/image/202306/d57905b93540bd15f0c48230dbbbff7ee0d645ff539e38866e2d15c8b9f7dfcd.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202306/d57905b93540bd15f0c48230dbbbff7ee0d645ff539e38866e2d15c8b9f7dfcd.png?imageMogr2/format/webp",
"600001859", "600001859",
"2022576801", "2022576801",
@@ -30,7 +23,7 @@ object TVList {
"CCTV2", "CCTV2",
listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226195/index.m3u8"), listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226195/index.m3u8"),
0, 0,
"央视", "央视频道",
"https://resources.yangshipin.cn/assets/oms/image/202306/20115388de0207131af17eac86c33049b95d69eaff064e55653a1b941810a006.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202306/20115388de0207131af17eac86c33049b95d69eaff064e55653a1b941810a006.png?imageMogr2/format/webp",
"600001800", "600001800",
"2022576701", "2022576701",
@@ -44,7 +37,7 @@ object TVList {
"CCTV3", "CCTV3",
listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226397/index.m3u8"), listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226397/index.m3u8"),
0, 0,
"央视", "央视频道",
"https://resources.yangshipin.cn/assets/oms/image/202306/7b7a65c712450da3deb6ca66fbacf4f9aee00d3f20bd80eafb5ada01ec63eb3a.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202306/7b7a65c712450da3deb6ca66fbacf4f9aee00d3f20bd80eafb5ada01ec63eb3a.png?imageMogr2/format/webp",
"600001801", "600001801",
"2022576501", "2022576501",
@@ -61,7 +54,7 @@ object TVList {
"http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226191/index.m3u8" "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226191/index.m3u8"
), ),
0, 0,
"央视", "央视频道",
"https://resources.yangshipin.cn/assets/oms/image/202306/f357e58fdbcc076a3d65e1f958c942b2e14f14342c60736ceed98b092d35356a.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202306/f357e58fdbcc076a3d65e1f958c942b2e14f14342c60736ceed98b092d35356a.png?imageMogr2/format/webp",
"600001814", "600001814",
"2022576601", "2022576601",
@@ -75,7 +68,7 @@ object TVList {
"CCTV5", "CCTV5",
listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226395/index.m3u8"), listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226395/index.m3u8"),
0, 0,
"央视", "央视频道",
"https://resources.yangshipin.cn/assets/oms/image/202306/0a6a7138952675983a3d854df7688557b286d59aa06166edae51506f9204d655.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202306/0a6a7138952675983a3d854df7688557b286d59aa06166edae51506f9204d655.png?imageMogr2/format/webp",
"600001818", "600001818",
"2022576401", "2022576401",
@@ -89,7 +82,7 @@ object TVList {
"CCTV6", "CCTV6",
listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226393/index.m3u8"), listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226393/index.m3u8"),
0, 0,
"央视", "央视频道",
"https://resources.yangshipin.cn/assets/oms/image/202306/741515efda91f03f455df8a7da4ee11fa9329139c276435cf0a9e2af398d5bf2.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202306/741515efda91f03f455df8a7da4ee11fa9329139c276435cf0a9e2af398d5bf2.png?imageMogr2/format/webp",
"600108442", "600108442",
"2013693901", "2013693901",
@@ -103,7 +96,7 @@ object TVList {
"CCTV7", "CCTV7",
listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226192/index.m3u8"), listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226192/index.m3u8"),
0, 0,
"央视", "央视频道",
"https://resources.yangshipin.cn/assets/oms/image/202306/b29af94e295ebdf646cefb68122c429b9cd921f498ca20d2d8070252536f9ff9.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202306/b29af94e295ebdf646cefb68122c429b9cd921f498ca20d2d8070252536f9ff9.png?imageMogr2/format/webp",
"600004092", "600004092",
"2022576201", "2022576201",
@@ -117,7 +110,7 @@ object TVList {
"CCTV8", "CCTV8",
listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226391/index.m3u8"), listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226391/index.m3u8"),
0, 0,
"央视", "央视频道",
"https://resources.yangshipin.cn/assets/oms/image/202306/ad51de94426a0ba039e6dd6a8534ea98ecc813a6176bde87b4f18cc34d6d7590.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202306/ad51de94426a0ba039e6dd6a8534ea98ecc813a6176bde87b4f18cc34d6d7590.png?imageMogr2/format/webp",
"600001803", "600001803",
"2022576101", "2022576101",
@@ -131,7 +124,7 @@ object TVList {
"CCTV9", "CCTV9",
listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226197/index.m3u8"), listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226197/index.m3u8"),
0, 0,
"央视", "央视频道",
"https://resources.yangshipin.cn/assets/oms/image/202306/2ed1b4deeca179d5db806bb941790f82eb92a1b7299c1c38fe027f95a5caee5e.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202306/2ed1b4deeca179d5db806bb941790f82eb92a1b7299c1c38fe027f95a5caee5e.png?imageMogr2/format/webp",
"600004078", "600004078",
"2022576001", "2022576001",
@@ -145,7 +138,7 @@ object TVList {
"CCTV10", "CCTV10",
listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226189/index.m3u8"), listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226189/index.m3u8"),
0, 0,
"央视", "央视频道",
"https://resources.yangshipin.cn/assets/oms/image/202306/aa6157ec65188cd41826e5a2f088c3d6d153205f5f6428258d12c59999e221aa.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202306/aa6157ec65188cd41826e5a2f088c3d6d153205f5f6428258d12c59999e221aa.png?imageMogr2/format/webp",
"600001805", "600001805",
"2022573001", "2022573001",
@@ -159,7 +152,7 @@ object TVList {
"CCTV11", "CCTV11",
listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226240/index.m3u8"), listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226240/index.m3u8"),
0, 0,
"央视", "央视频道",
"https://resources.yangshipin.cn/assets/oms/image/202306/ed12ed7c7a1034dae4350011fe039284c5d5a836506b28c9e32e3c75299625c0.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202306/ed12ed7c7a1034dae4350011fe039284c5d5a836506b28c9e32e3c75299625c0.png?imageMogr2/format/webp",
"600001806", "600001806",
"2022575901", "2022575901",
@@ -173,7 +166,7 @@ object TVList {
"CCTV12", "CCTV12",
listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226190/index.m3u8"), listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226190/index.m3u8"),
0, 0,
"央视", "央视频道",
"https://resources.yangshipin.cn/assets/oms/image/202306/484083cffaa40df7e659565e8cb4d1cc740158a185512114167aa21fa0c59240.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202306/484083cffaa40df7e659565e8cb4d1cc740158a185512114167aa21fa0c59240.png?imageMogr2/format/webp",
"600001807", "600001807",
"2022575801", "2022575801",
@@ -190,7 +183,7 @@ object TVList {
"http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226233/index.m3u8" "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226233/index.m3u8"
), ),
0, 0,
"央视", "央视频道",
"https://resources.yangshipin.cn/assets/oms/image/202306/266da7b43c03e2312186b4a999e0f060e8f15b10d2cc2c9aa32171819254cf1a.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202306/266da7b43c03e2312186b4a999e0f060e8f15b10d2cc2c9aa32171819254cf1a.png?imageMogr2/format/webp",
"600001811", "600001811",
"2022575701", "2022575701",
@@ -204,7 +197,7 @@ object TVList {
"CCTV14", "CCTV14",
listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226193/index.m3u8"), listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226193/index.m3u8"),
0, 0,
"央视", "央视频道",
"https://resources.yangshipin.cn/assets/oms/image/202306/af6b603896938dc346fbb16abfc63c12cba54b0ec9d18770a15d347d115f12d5.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202306/af6b603896938dc346fbb16abfc63c12cba54b0ec9d18770a15d347d115f12d5.png?imageMogr2/format/webp",
"600001809", "600001809",
"2022575601", "2022575601",
@@ -218,7 +211,7 @@ object TVList {
"CCTV15", "CCTV15",
listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225785/index.m3u8"), listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225785/index.m3u8"),
0, 0,
"央视", "央视频道",
"https://resources.yangshipin.cn/assets/oms/image/202306/2ceee92188ef684efe0d8b90839c4f3ad450d179dc64d59beff417059453af47.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202306/2ceee92188ef684efe0d8b90839c4f3ad450d179dc64d59beff417059453af47.png?imageMogr2/format/webp",
"600001815", "600001815",
"2022575501", "2022575501",
@@ -235,7 +228,7 @@ object TVList {
"http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226921/index.m3u8" "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226921/index.m3u8"
), ),
0, 0,
"央视", "央视频道",
"https://resources.yangshipin.cn/assets/oms/image/202306/53793fa7bacd3a93ff6dc5d2758418985e1f952a316c335d663b572d8bdcd74d.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202306/53793fa7bacd3a93ff6dc5d2758418985e1f952a316c335d663b572d8bdcd74d.png?imageMogr2/format/webp",
"600098637", "600098637",
"2022575401", "2022575401",
@@ -249,7 +242,7 @@ object TVList {
"CCTV17", "CCTV17",
listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226198/index.m3u8"), listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226198/index.m3u8"),
0, 0,
"央视", "央视频道",
"https://resources.yangshipin.cn/assets/oms/image/202306/ddef563072f8bad2bea5b9e52674cb7b4ed50efb20c26e61994dfbdf05c1e3c0.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202306/ddef563072f8bad2bea5b9e52674cb7b4ed50efb20c26e61994dfbdf05c1e3c0.png?imageMogr2/format/webp",
"600001810", "600001810",
"2022575301", "2022575301",
@@ -263,7 +256,7 @@ object TVList {
"CCTV5+", "CCTV5+",
listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226221/index.m3u8"), listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226221/index.m3u8"),
0, 0,
"央视", "央视频道",
"https://resources.yangshipin.cn/assets/oms/image/202306/649ad76a90bfef55b05db9fe52e006487280f619089099d5dc971e387fc6eff0.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202306/649ad76a90bfef55b05db9fe52e006487280f619089099d5dc971e387fc6eff0.png?imageMogr2/format/webp",
"600001817", "600001817",
"2022576301", "2022576301",
@@ -277,7 +270,7 @@ object TVList {
"CCTV4K", "CCTV4K",
listOf(), listOf(),
0, 0,
"央视", "央视频道",
"https://resources.yangshipin.cn/assets/oms/image/202306/3e9d06fd7244d950df5838750f1c6ac3456e172b51caca2c16d2282125b111e8.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202306/3e9d06fd7244d950df5838750f1c6ac3456e172b51caca2c16d2282125b111e8.png?imageMogr2/format/webp",
"600002264", "600002264",
"2022575201", "2022575201",
@@ -291,7 +284,7 @@ object TVList {
"CCTV8K", "CCTV8K",
listOf(), listOf(),
0, 0,
"央视", "央视频道",
"", "",
"600156816", "600156816",
"2020603421", "2020603421",
@@ -305,7 +298,7 @@ object TVList {
"CCTV风云剧场频道", "CCTV风云剧场频道",
listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226950/index.m3u8"), listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226950/index.m3u8"),
0, 0,
"央视", "央视频道",
"https://resources.yangshipin.cn/assets/oms/image/202306/4d549e53e6d0f632d5a633d1945280797b153e588f919221a07faa869812cc89.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202306/4d549e53e6d0f632d5a633d1945280797b153e588f919221a07faa869812cc89.png?imageMogr2/format/webp",
"600099658", "600099658",
"2012513603", "2012513603",
@@ -319,7 +312,7 @@ object TVList {
"CCTV第一剧场频道", "CCTV第一剧场频道",
listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226959/index.m3u8"), listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226959/index.m3u8"),
0, 0,
"央视", "央视频道",
"https://resources.yangshipin.cn/assets/oms/image/202306/a556bd7d93ce65e18f243a8892b5604f4faa994a4897315914216a710a706208.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202306/a556bd7d93ce65e18f243a8892b5604f4faa994a4897315914216a710a706208.png?imageMogr2/format/webp",
"600099655", "600099655",
"2012514403", "2012514403",
@@ -333,7 +326,7 @@ object TVList {
"CCTV怀旧剧场频道", "CCTV怀旧剧场频道",
listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226972/index.m3u8"), listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226972/index.m3u8"),
0, 0,
"央视", "央视频道",
"https://resources.yangshipin.cn/assets/oms/image/202306/5661bd04fecdb6e899f801147a22ab5d3a475bf2b62e30aec2c0023190ebc9b1.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202306/5661bd04fecdb6e899f801147a22ab5d3a475bf2b62e30aec2c0023190ebc9b1.png?imageMogr2/format/webp",
"600099620", "600099620",
"2012511203", "2012511203",
@@ -347,7 +340,7 @@ object TVList {
"CCTV世界地理频道", "CCTV世界地理频道",
listOf(), listOf(),
0, 0,
"央视", "央视频道",
"https://resources.yangshipin.cn/assets/oms/image/202306/bb3c6c9e145d698137f5bb64a582021a01b51344b929003630eb769ea65832a9.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202306/bb3c6c9e145d698137f5bb64a582021a01b51344b929003630eb769ea65832a9.png?imageMogr2/format/webp",
"600099637", "600099637",
"2012513303", "2012513303",
@@ -361,7 +354,7 @@ object TVList {
"CCTV风云音乐频道", "CCTV风云音乐频道",
listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226953/index.m3u8"), listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226953/index.m3u8"),
0, 0,
"央视", "央视频道",
"https://resources.yangshipin.cn/assets/oms/image/202306/bbf1d024c5228b8dd128b0e3cb1717d173fab4ee84c3a4c8a57b1a215362ca3b.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202306/bbf1d024c5228b8dd128b0e3cb1717d173fab4ee84c3a4c8a57b1a215362ca3b.png?imageMogr2/format/webp",
"600099660", "600099660",
"2012514103", "2012514103",
@@ -375,7 +368,7 @@ object TVList {
"CCTV兵器科技频道", "CCTV兵器科技频道",
listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226975/index.m3u8"), listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226975/index.m3u8"),
0, 0,
"央视", "央视频道",
"https://resources.yangshipin.cn/assets/oms/image/202306/4c6b6a6d3839889f34d33db3c2f80233b26b74d3489b393487635f8704e70796.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202306/4c6b6a6d3839889f34d33db3c2f80233b26b74d3489b393487635f8704e70796.png?imageMogr2/format/webp",
"600099649", "600099649",
"2012513403", "2012513403",
@@ -389,7 +382,7 @@ object TVList {
"CCTV风云足球频道", "CCTV风云足球频道",
listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226984/index.m3u8"), listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226984/index.m3u8"),
0, 0,
"央视", "央视频道",
"https://resources.yangshipin.cn/assets/oms/image/202306/cd1e2bb52b06a991de168733e5ff0f1d85adc8042d40c8f393f723543e5dd08a.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202306/cd1e2bb52b06a991de168733e5ff0f1d85adc8042d40c8f393f723543e5dd08a.png?imageMogr2/format/webp",
"600099636", "600099636",
"2012514203", "2012514203",
@@ -403,7 +396,7 @@ object TVList {
"CCTV高尔夫·网球频道", "CCTV高尔夫·网球频道",
listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226978/index.m3u8"), listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226978/index.m3u8"),
0, 0,
"央视", "央视频道",
"https://resources.yangshipin.cn/assets/oms/image/202306/cdd1b31ede7a5ad049ed53d9a072422f829e72dd062ed2c19e077fdd01699071.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202306/cdd1b31ede7a5ad049ed53d9a072422f829e72dd062ed2c19e077fdd01699071.png?imageMogr2/format/webp",
"600099659", "600099659",
"2012512503", "2012512503",
@@ -417,7 +410,7 @@ object TVList {
"CCTV女性时尚频道", "CCTV女性时尚频道",
listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226969/index.m3u8"), listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226969/index.m3u8"),
0, 0,
"央视", "央视频道",
"https://resources.yangshipin.cn/assets/oms/image/202306/fa28955ce8b2539d728bf4c6a13a46ff57ad76eae46627f7bcfb1ed8a613d3fc.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202306/fa28955ce8b2539d728bf4c6a13a46ff57ad76eae46627f7bcfb1ed8a613d3fc.png?imageMogr2/format/webp",
"600099650", "600099650",
"2012513903", "2012513903",
@@ -431,7 +424,7 @@ object TVList {
"CCTV央视文化精品频道", "CCTV央视文化精品频道",
listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226981/index.m3u8"), listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226981/index.m3u8"),
0, 0,
"央视", "央视频道",
"https://resources.yangshipin.cn/assets/oms/image/202306/14ac5ce40482cacd3d4b37435222bfe86af2b452a2f04ecbfc1d13d76edd7c57.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202306/14ac5ce40482cacd3d4b37435222bfe86af2b452a2f04ecbfc1d13d76edd7c57.png?imageMogr2/format/webp",
"600099653", "600099653",
"2012513803", "2012513803",
@@ -445,7 +438,7 @@ object TVList {
"CCTV央视台球频道", "CCTV央视台球频道",
listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226956/index.m3u8"), listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226956/index.m3u8"),
0, 0,
"央视", "央视频道",
"https://resources.yangshipin.cn/assets/oms/image/202306/10e14a92478011aa6c3c8562e62127f3b1908e29fcd78e4b2b24b9e6d3ec2fbc.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202306/10e14a92478011aa6c3c8562e62127f3b1908e29fcd78e4b2b24b9e6d3ec2fbc.png?imageMogr2/format/webp",
"600099652", "600099652",
"2012513703", "2012513703",
@@ -459,7 +452,7 @@ object TVList {
"CCTV电视指南频道", "CCTV电视指南频道",
listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226987/index.m3u8"), listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226987/index.m3u8"),
0, 0,
"央视", "央视频道",
"https://resources.yangshipin.cn/assets/oms/image/202306/244d72c0eb1615ed7d51c2f5db5a67f306aa3f58c05bc2d34de3aa7e956dc8c9.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202306/244d72c0eb1615ed7d51c2f5db5a67f306aa3f58c05bc2d34de3aa7e956dc8c9.png?imageMogr2/format/webp",
"600099656", "600099656",
"2012514003", "2012514003",
@@ -473,7 +466,7 @@ object TVList {
"CCTV卫生健康频道", "CCTV卫生健康频道",
listOf(), listOf(),
0, 0,
"央视", "央视频道",
"https://resources.yangshipin.cn/assets/oms/image/202306/54a6863656fdfd8f803be193ddf22441c5000a108833889816fd2d8911715ce8.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202306/54a6863656fdfd8f803be193ddf22441c5000a108833889816fd2d8911715ce8.png?imageMogr2/format/webp",
"600099651", "600099651",
"2012513503", "2012513503",
@@ -482,14 +475,14 @@ object TVList {
mustToken = true mustToken = true
), ),
), ),
"地方" to listOf( "地方频道" to listOf(
TV( TV(
33, 33,
"东方卫视", "东方卫视",
"东方卫视", "东方卫视",
listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226217/index.m3u8"), listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226217/index.m3u8"),
0, 0,
"地方", "地方频道",
"https://resources.yangshipin.cn/assets/oms/image/202306/9bd372ca292a82ce3aa08772b07efc4af1f85c21d1f268ea33440c49e9a0a488.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202306/9bd372ca292a82ce3aa08772b07efc4af1f85c21d1f268ea33440c49e9a0a488.png?imageMogr2/format/webp",
"600002483", "600002483",
"2000292403", "2000292403",
@@ -506,7 +499,7 @@ object TVList {
"http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226211/index.m3u8" "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226211/index.m3u8"
), ),
0, 0,
"地方", "地方频道",
"https://resources.yangshipin.cn/assets/oms/image/202306/4120e89d3079d08aa17d382f69a2308ec70839b278367763c34a34666c75cb88.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202306/4120e89d3079d08aa17d382f69a2308ec70839b278367763c34a34666c75cb88.png?imageMogr2/format/webp",
"600002475", "600002475",
"2000296203", "2000296203",
@@ -523,7 +516,7 @@ object TVList {
"http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226194/index.m3u8" "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226194/index.m3u8"
), ),
0, 0,
"地方", "地方频道",
"https://resources.yangshipin.cn/assets/oms/image/202306/7a6be5a2bb1dc53a945c016ff1f525dc4a84c51db371c15c89aa55404b0ba784.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202306/7a6be5a2bb1dc53a945c016ff1f525dc4a84c51db371c15c89aa55404b0ba784.png?imageMogr2/format/webp",
"600002508", "600002508",
"2000294503", "2000294503",
@@ -540,7 +533,7 @@ object TVList {
"http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226201/index.m3u8" "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226201/index.m3u8"
), ),
0, 0,
"地方", "地方频道",
"https://resources.yangshipin.cn/assets/oms/image/202306/ac4ed6058a87c101ae7147ebc38905d0cae047fb73fd277ee5049b84f52bda36.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202306/ac4ed6058a87c101ae7147ebc38905d0cae047fb73fd277ee5049b84f52bda36.png?imageMogr2/format/webp",
"600002505", "600002505",
"2000281303", "2000281303",
@@ -557,7 +550,7 @@ object TVList {
"http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226200/index.m3u8" "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226200/index.m3u8"
), ),
0, 0,
"地方", "地方频道",
"https://resources.yangshipin.cn/assets/oms/image/202306/380ad685c0c1d5b2c902246b8d2df6d3f9b45e2837abcfe493075bbded597a31.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202306/380ad685c0c1d5b2c902246b8d2df6d3f9b45e2837abcfe493075bbded597a31.png?imageMogr2/format/webp",
"600002521", "600002521",
"2000295603", "2000295603",
@@ -574,7 +567,7 @@ object TVList {
"http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225764/index.m3u8" "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225764/index.m3u8"
), ),
0, 0,
"地方", "地方频道",
"https://resources.yangshipin.cn/assets/oms/image/202306/3c760d0d00463855890e8a1864ea4a6b6dd66b90c29b4ac714a4b17c16519871.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202306/3c760d0d00463855890e8a1864ea4a6b6dd66b90c29b4ac714a4b17c16519871.png?imageMogr2/format/webp",
"600002503", "600002503",
"2000294103", "2000294103",
@@ -588,7 +581,7 @@ object TVList {
"山东卫视", "山东卫视",
listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226209/index.m3u8"), listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226209/index.m3u8"),
0, 0,
"地方", "地方频道",
"https://resources.yangshipin.cn/assets/oms/image/202306/22d403f07a7cf5410b3ad3ddb65a11aa229a32475fac213f5344c9f0ec330ca1.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202306/22d403f07a7cf5410b3ad3ddb65a11aa229a32475fac213f5344c9f0ec330ca1.png?imageMogr2/format/webp",
"600002513", "600002513",
"2000294803", "2000294803",
@@ -602,7 +595,7 @@ object TVList {
"广东卫视", "广东卫视",
listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226216/index.m3u8"), listOf("http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226216/index.m3u8"),
0, 0,
"地方", "地方频道",
"https://resources.yangshipin.cn/assets/oms/image/202306/28886880a4dc0f06fb7e0a528a1def0591d61a65870e29176ede0cc92033bbfd.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202306/28886880a4dc0f06fb7e0a528a1def0591d61a65870e29176ede0cc92033bbfd.png?imageMogr2/format/webp",
"600002485", "600002485",
"2000292703", "2000292703",
@@ -619,7 +612,7 @@ object TVList {
"http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225770/index.m3u8" "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225770/index.m3u8"
), ),
0, 0,
"地方", "地方频道",
"https://resources.yangshipin.cn/assets/oms/image/202306/54b7e97cb816bb223fe05f3fc44da2c7820eb66e8550c19d23100f2c414ecc38.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202306/54b7e97cb816bb223fe05f3fc44da2c7820eb66e8550c19d23100f2c414ecc38.png?imageMogr2/format/webp",
"600002509", "600002509",
"2000294203", "2000294203",
@@ -636,7 +629,7 @@ object TVList {
"http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226202/index.m3u8" "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226202/index.m3u8"
), ),
0, 0,
"地方", "地方频道",
"https://resources.yangshipin.cn/assets/oms/image/202306/657651f411de2673d1770d9a78b44c1265704f7468cc41d4be7f51d630768494.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202306/657651f411de2673d1770d9a78b44c1265704f7468cc41d4be7f51d630768494.png?imageMogr2/format/webp",
"600002531", "600002531",
"2000297803", "2000297803",
@@ -653,7 +646,7 @@ object TVList {
"http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225767/index.m3u8" "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225767/index.m3u8"
), ),
0, 0,
"地方", "地方频道",
"https://resources.yangshipin.cn/assets/oms/image/202306/74925962148a6d31c85808b6cd4e444c2a54bab393d2c5fc85e960b50e22fa86.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202306/74925962148a6d31c85808b6cd4e444c2a54bab393d2c5fc85e960b50e22fa86.png?imageMogr2/format/webp",
"600002525", "600002525",
"2000296103", "2000296103",
@@ -670,7 +663,7 @@ object TVList {
"http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225750/index.m3u8" "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225750/index.m3u8"
), ),
0, 0,
"地方", "地方频道",
"https://resources.yangshipin.cn/assets/oms/image/202306/d545becdc81c60197b08c7f47380705e4665ed3fe55efc8b855e486f6e655378.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202306/d545becdc81c60197b08c7f47380705e4665ed3fe55efc8b855e486f6e655378.png?imageMogr2/format/webp",
"600002493", "600002493",
"2000293403", "2000293403",
@@ -687,7 +680,7 @@ object TVList {
"http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225793/index.m3u8" "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225793/index.m3u8"
), ),
0, 0,
"地方", "地方频道",
"https://resources.yangshipin.cn/assets/oms/image/202306/4eb45f4781d33d872af027dc01c941559aab55667dd99cc5c22bef7037807b13.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202306/4eb45f4781d33d872af027dc01c941559aab55667dd99cc5c22bef7037807b13.png?imageMogr2/format/webp",
"600002490", "600002490",
"2000293303", "2000293303",
@@ -704,7 +697,7 @@ object TVList {
"http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226222/index.m3u8" "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226222/index.m3u8"
), ),
0, 0,
"地方", "地方频道",
"https://resources.yangshipin.cn/assets/oms/image/202306/f4f23633c578beea49a3841d88d3490100f029ee349059fa532869db889872c5.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202306/f4f23633c578beea49a3841d88d3490100f029ee349059fa532869db889872c5.png?imageMogr2/format/webp",
"600002309", "600002309",
"2000272103", "2000272103",
@@ -721,7 +714,7 @@ object TVList {
"http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226215/index.m3u8" "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226215/index.m3u8"
), ),
0, 0,
"地方", "地方频道",
"https://resources.yangshipin.cn/assets/oms/image/202306/d8273ae9be698ce2db21f5b886ecac95a73429593f93713c60ed8c12c38bf0d3.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202306/d8273ae9be698ce2db21f5b886ecac95a73429593f93713c60ed8c12c38bf0d3.png?imageMogr2/format/webp",
"600002498", "600002498",
"2000293903", "2000293903",
@@ -738,7 +731,7 @@ object TVList {
"http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226199/index.m3u8" "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226199/index.m3u8"
), ),
0, 0,
"地方", "地方频道",
"https://resources.yangshipin.cn/assets/oms/image/202306/a66c836bd98ba3e41a2e9a570d4b9c50dedc6839e9de333e2e78212ad505f37e.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202306/a66c836bd98ba3e41a2e9a570d4b9c50dedc6839e9de333e2e78212ad505f37e.png?imageMogr2/format/webp",
"600002520", "600002520",
"2000295503", "2000295503",
@@ -755,7 +748,7 @@ object TVList {
"http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226203/index.m3u8" "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226203/index.m3u8"
), ),
0, 0,
"地方", "地方频道",
"https://resources.yangshipin.cn/assets/oms/image/202306/f35fa04b51b1ee4984b03578b65403570868ebca03c6c01e11b097f999a58d9b.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202306/f35fa04b51b1ee4984b03578b65403570868ebca03c6c01e11b097f999a58d9b.png?imageMogr2/format/webp",
"600002532", "600002532",
"2000298003", "2000298003",
@@ -772,7 +765,7 @@ object TVList {
"http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226205/index.m3u8" "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226205/index.m3u8"
), ),
0, 0,
"地方", "地方频道",
"https://resources.yangshipin.cn/assets/oms/image/202306/d59fec04c902e3581c617136d02d4b9b8c4cbe64272781ddd3525e80c823edb7.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202306/d59fec04c902e3581c617136d02d4b9b8c4cbe64272781ddd3525e80c823edb7.png?imageMogr2/format/webp",
"600002481", "600002481",
"2000292203", "2000292203",
@@ -789,7 +782,7 @@ object TVList {
"http://39.134.24.166/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"
), ),
0, 0,
"地方", "地方频道",
"https://resources.yangshipin.cn/assets/oms/image/202306/3276a414ae0eaa0f116f2045cd913367967d0c7c1e978e8621ac3879436c6ed7.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202306/3276a414ae0eaa0f116f2045cd913367967d0c7c1e978e8621ac3879436c6ed7.png?imageMogr2/format/webp",
"600002516", "600002516",
"2000295003", "2000295003",
@@ -806,7 +799,7 @@ object TVList {
"http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225766/index.m3u8" "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225766/index.m3u8"
), ),
0, 0,
"地方", "地方频道",
"https://resources.yangshipin.cn/assets/oms/image/202306/3208fe6564a293c21b711333fb3edb05bb5b406cff840573c9a8d839680a1579.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202306/3208fe6564a293c21b711333fb3edb05bb5b406cff840573c9a8d839680a1579.png?imageMogr2/format/webp",
"600002484", "600002484",
"2000292503", "2000292503",
@@ -823,7 +816,7 @@ object TVList {
"http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225769/index.m3u8" "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225769/index.m3u8"
), ),
0, 0,
"地方", "地方频道",
"https://resources.yangshipin.cn/assets/oms/image/202306/6e060391fde0469801fc3d84dbf204b4f8d650d251f17d7595a6964c0bb99e81.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202306/6e060391fde0469801fc3d84dbf204b4f8d650d251f17d7595a6964c0bb99e81.png?imageMogr2/format/webp",
"600002506", "600002506",
"2000291503", "2000291503",
@@ -837,7 +830,7 @@ object TVList {
"天津卫视", "天津卫视",
listOf(), listOf(),
0, 0,
"地方", "地方频道",
"", "",
"600152137", "600152137",
"2019927003", "2019927003",
@@ -851,7 +844,7 @@ object TVList {
"新疆卫视", "新疆卫视",
listOf(), listOf(),
0, 0,
"地方", "地方频道",
"", "",
"600152138", "600152138",
"2019927403", "2019927403",
@@ -865,7 +858,7 @@ object TVList {
"兵团卫视", "兵团卫视",
listOf(), listOf(),
0, 0,
"地方", "地方频道",
"", "",
"600170344", "600170344",
"2022606701", "2022606701",
@@ -873,73 +866,15 @@ object TVList {
true, true,
mustToken = false mustToken = false
), ),
),
"国际频道" to listOf(
TV( TV(
57, 57,
"CETV1",
"CETV1",
listOf(),
0,
"地方",
"",
"600171827",
"2022823801",
"",
true,
mustToken = false
),
),
"港澳台" to listOf(
TV(
58,
"凤凰卫视资讯台",
"",
listOf(),
0,
"港澳台",
"http://c1.fengshows-cdn.com/a/2021_22/79dcc3a9da358a3.png",
"7c96b084-60e1-40a9-89c5-682b994fb680",
"",
"",
false,
mustToken = false
),
TV(
59,
"凤凰卫视中文台",
"",
listOf(),
0,
"港澳台",
"http://c1.fengshows-cdn.com/a/2021_22/ede3d9e09be28e5.png",
"f7f48462-9b13-485b-8101-7b54716411ec",
"",
"",
false,
mustToken = false
),
TV(
60,
"凤凰卫视香港台",
"",
listOf(),
0,
"港澳台",
"http://c1.fengshows-cdn.com/a/2021_23/325d941090bee17.png",
"15e02d92-1698-416c-af2f-3e9a872b4d78",
"",
"",
false,
mustToken = false
),
),
"国际" to listOf(
TV(
61,
"CGTN", "CGTN",
"CGTN", "CGTN",
listOf("http://live.cgtn.com/1000/prog_index.m3u8"), listOf("http://live.cgtn.com/1000/prog_index.m3u8"),
0, 0,
"国际", "国际频道",
"https://resources.yangshipin.cn/assets/oms/image/202306/a72dff758ca1c17cd0ecc8cedc11b893d208f409d5e6302faa0e9d298848abc3.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202306/a72dff758ca1c17cd0ecc8cedc11b893d208f409d5e6302faa0e9d298848abc3.png?imageMogr2/format/webp",
"600014550", "600014550",
"2022575001", "2022575001",
@@ -948,12 +883,12 @@ object TVList {
mustToken = false mustToken = false
), ),
TV( TV(
62, 58,
"CGTN 法语频道", "CGTN 法语频道",
"CGTN法语频道", "CGTN法语频道",
listOf("https://livefr.cgtn.com/1000f/prog_index.m3u8"), listOf("https://livefr.cgtn.com/1000f/prog_index.m3u8"),
0, 0,
"国际", "国际频道",
"https://resources.yangshipin.cn/assets/oms/image/202306/a8d0046a47433d952bf6ed17062deb8bd2184ba9aec0f7781df6bf9487a3ffcf.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202306/a8d0046a47433d952bf6ed17062deb8bd2184ba9aec0f7781df6bf9487a3ffcf.png?imageMogr2/format/webp",
"600084704", "600084704",
"2022574901", "2022574901",
@@ -962,12 +897,12 @@ object TVList {
mustToken = false mustToken = false
), ),
TV( TV(
63, 59,
"CGTN 俄语频道", "CGTN 俄语频道",
"CGTN俄语频道", "CGTN俄语频道",
listOf("http://liveru.cgtn.com/1000r/prog_index.m3u8"), listOf("http://liveru.cgtn.com/1000r/prog_index.m3u8"),
0, 0,
"国际", "国际频道",
"https://resources.yangshipin.cn/assets/oms/image/202306/bf0a820893cbaf20dd0333e27042e1ef9c8806e5b602b6a8c95af399db0bc77a.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202306/bf0a820893cbaf20dd0333e27042e1ef9c8806e5b602b6a8c95af399db0bc77a.png?imageMogr2/format/webp",
"600084758", "600084758",
"2022574801", "2022574801",
@@ -976,12 +911,12 @@ object TVList {
mustToken = false mustToken = false
), ),
TV( TV(
64, 60,
"CGTN 阿拉伯语频道", "CGTN 阿拉伯语频道",
"CGTN阿拉伯语频道", "CGTN阿拉伯语频道",
listOf("http://livear.cgtn.com/1000a/prog_index.m3u8"), listOf("http://livear.cgtn.com/1000a/prog_index.m3u8"),
0, 0,
"国际", "国际频道",
"https://resources.yangshipin.cn/assets/oms/image/202306/2e44e2aa3e7a1cedf07fd0ae59fe69e86a60a2632660a006e3e9e7397b2d107e.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202306/2e44e2aa3e7a1cedf07fd0ae59fe69e86a60a2632660a006e3e9e7397b2d107e.png?imageMogr2/format/webp",
"600084782", "600084782",
"2022574601", "2022574601",
@@ -990,7 +925,7 @@ object TVList {
mustToken = false mustToken = false
), ),
TV( TV(
65, 61,
"CGTN 西班牙语频道", "CGTN 西班牙语频道",
"CGTN西班牙语频道", "CGTN西班牙语频道",
listOf( listOf(
@@ -998,7 +933,7 @@ object TVList {
"http://livees.cgtn.com/1000e/prog_index.m3u8" "http://livees.cgtn.com/1000e/prog_index.m3u8"
), ),
0, 0,
"国际", "国际频道",
"https://resources.yangshipin.cn/assets/oms/image/202309/7c337e3dbe64402ec7e4678a619a4a6d95144e42f35161181ff78e143b7cf67a.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202309/7c337e3dbe64402ec7e4678a619a4a6d95144e42f35161181ff78e143b7cf67a.png?imageMogr2/format/webp",
"600084744", "600084744",
"2022571701", "2022571701",
@@ -1007,12 +942,12 @@ object TVList {
mustToken = false mustToken = false
), ),
TV( TV(
66, 62,
"CGTN 纪录频道", "CGTN 纪录频道",
"CGTN外语纪录频道", "CGTN外语纪录频道",
listOf("https://livedoc.cgtn.com/500d/prog_index.m3u8"), listOf("https://livedoc.cgtn.com/500d/prog_index.m3u8"),
0, 0,
"国际", "国际频道",
"https://resources.yangshipin.cn/assets/oms/image/202309/74d3ac436a7e374879578de1d87a941fbf566d39d5632b027c5097891ed32bd5.png?imageMogr2/format/webp", "https://resources.yangshipin.cn/assets/oms/image/202309/74d3ac436a7e374879578de1d87a941fbf566d39d5632b027c5097891ed32bd5.png?imageMogr2/format/webp",
"600084781", "600084781",
"2022574701", "2022574701",
@@ -1022,63 +957,4 @@ object TVList {
), ),
) )
) )
/**
* 初始化
*
* @param context Context
*/
fun init(context: Context) {
CoroutineScope(Dispatchers.Default).launch {
//获取本地版本号
val localVersion = ChannelUtils.getLocalVersion(context)
//获取服务器版本号
val serverVersion = try {
ChannelUtils.getServerVersion(context)
} catch (e: IOException) {
Log.e("TVList", "无法从服务器获取版本信息", e)
Integer.MIN_VALUE
}
//频道列表
val channelTVMap: MutableMap<String, MutableList<TV>> = mutableMapOf()
//是否从服务器更新
var updateFromServer = false
//获取频道列表
val tvList: List<TV> = if (localVersion < serverVersion) {
//获取服务器地址
val url = ChannelUtils.getServerUrl(context)
//是否从服务器更新
updateFromServer = true
Log.i("TVList", "从服务器获取频道信息")
try {
ChannelUtils.getServerChannel(url)
} catch (e: IOException) {
Log.e("TVList", "无法从服务器获取频道信息", e)
updateFromServer = false
ChannelUtils.getLocalChannel(context)
}
} else {
Log.i("TVList", "从本地获取频道信息")
//获取本地频道
ChannelUtils.getLocalChannel(context)
}
//按频道分类
for (tv in tvList) {
val key = tv.channel
if (channelTVMap.containsKey(key)) {
val list = channelTVMap[key]!!
list.add(tv)
channelTVMap[key] = list
} else {
channelTVMap[key] = mutableListOf(tv)
}
}
//保存频道列表
list = channelTVMap
//保存版本号
if (updateFromServer) {
ChannelUtils.updateLocalChannel(context, serverVersion, tvList)
}
}
}
} }
+47 -4
View File
@@ -1,5 +1,6 @@
package com.lizongying.mytv package com.lizongying.mytv
import android.content.Context
import android.content.res.Resources import android.content.res.Resources
import android.os.Build import android.os.Build
import android.util.TypedValue import android.util.TypedValue
@@ -7,6 +8,7 @@ import com.google.gson.Gson
import com.lizongying.mytv.api.TimeResponse import com.lizongying.mytv.api.TimeResponse
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import java.io.File
import java.io.IOException import java.io.IOException
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Date import java.util.Date
@@ -26,10 +28,6 @@ object Utils {
return (System.currentTimeMillis() - between) / 1000 return (System.currentTimeMillis() - between) / 1000
} }
fun setBetween(currentTimeMillis: Long) {
between = System.currentTimeMillis() - currentTimeMillis
}
suspend fun init() { suspend fun init() {
var currentTimeMillis: Long = 0 var currentTimeMillis: Long = 0
try { try {
@@ -78,4 +76,49 @@ object Utils {
} }
fun isTmallDevice() = Build.MANUFACTURER.equals("Tmall", ignoreCase = true) fun isTmallDevice() = Build.MANUFACTURER.equals("Tmall", ignoreCase = true)
/**
* 获取可读写的目录
*
* @param context 应用环境信息
*
* @return 可读写的目录
*
*/
fun getAppDirectory(context: Context): File {
return context.filesDir
}
/**
* 更新channels.json
*
* @param context 应用环境信息
*
* @return 无
*
* @throws IOException 网络请求失败
*/
fun updateChannel(context: Context) {
val client = okhttp3.OkHttpClient()
val request = okhttp3.Request.Builder().url(getServerUrl(context)).build()
client.newCall(request).execute().use { response ->
if (!response.isSuccessful) throw IOException("Unexpected code $response")
val body = response.body()
//覆盖channels.json
val file = File(getAppDirectory(context), "channels.json")
if (!file.exists()) {
file.createNewFile()
}
file.writeText(body!!.string())
}
}
/**
* 从res/values/server.xml获取服务器地址
* @param context 应用环境信息
* @return 服务器地址
*/
private fun getServerUrl(context: Context): String {
return context.resources.getString(R.string.server_url)
}
} }
@@ -16,7 +16,6 @@ class ApiClient {
private val devUrl = "http://10.0.2.2:8081/" private val devUrl = "http://10.0.2.2:8081/"
private val protoUrl = "https://capi.yangshipin.cn/" private val protoUrl = "https://capi.yangshipin.cn/"
private val traceUrl = "https://btrace.yangshipin.cn/" private val traceUrl = "https://btrace.yangshipin.cn/"
private val fUrl = "https://m.fengshows.com/"
private var okHttpClient = getUnsafeOkHttpClient() private var okHttpClient = getUnsafeOkHttpClient()
@@ -60,14 +59,6 @@ class ApiClient {
.build().create(YSPBtraceService::class.java) .build().create(YSPBtraceService::class.java)
} }
val fAuthService: FAuthService by lazy {
Retrofit.Builder()
.baseUrl(fUrl)
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.build().create(FAuthService::class.java)
}
private fun getUnsafeOkHttpClient(): OkHttpClient { private fun getUnsafeOkHttpClient(): OkHttpClient {
try { try {
val trustAllCerts: Array<TrustManager> = arrayOf( val trustAllCerts: Array<TrustManager> = arrayOf(
@@ -1,10 +0,0 @@
package com.lizongying.mytv.api
data class FAuth(
val data: Data,
) {
data class Data(
val live_url: String,
)
}
@@ -1,15 +0,0 @@
package com.lizongying.mytv.api
import retrofit2.Call
import retrofit2.http.GET
import retrofit2.http.Header
import retrofit2.http.Query
interface FAuthService {
@GET("api/v3/hub/live/auth-url")
fun getAuth(
@Header("token") token: String,
@Query("live_id") live_id: String = "",
@Query("live_qa") live_qa: String = "",
): Call<FAuth>
}
@@ -10,18 +10,6 @@ data class Info(
) )
} }
data class Token(
val e: Int?,
val t: String?,
)
data class InfoV2(
val f: String?,
val t: String?,
val e: Int?,
val c: Int?,
)
data class Release( data class Release(
val code: Int?, val code: Int?,
val msg: String?, val msg: String?,
@@ -1,17 +1,15 @@
package com.lizongying.mytv.api package com.lizongying.mytv.api
import android.content.Context import android.content.Context
import android.content.SharedPreferences
import com.lizongying.mytv.Encryptor import com.lizongying.mytv.Encryptor
import com.lizongying.mytv.MainActivity import com.lizongying.mytv.MainActivity
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
import kotlin.math.floor import kotlin.math.floor
import kotlin.random.Random import kotlin.random.Random
object YSP { class YSP(var context: Context) {
private const val TAG = "YSP"
private var cnlid = "" private var cnlid = ""
private var livepid = "" private var livepid = ""
@@ -55,10 +53,17 @@ object YSP {
private var appid = "ysp_pc" private var appid = "ysp_pc"
var token = "" var token = ""
private var encryptor = Encryptor() private var encryptor: Encryptor? = null
private lateinit var sharedPref: SharedPreferences
init {
if (context is MainActivity) {
encryptor = Encryptor()
encryptor!!.init(context)
sharedPref = (context as MainActivity).sharedPref
}
fun init(context: Context) {
encryptor.init(context)
guid = getGuid() guid = getGuid()
} }
@@ -76,7 +81,7 @@ object YSP {
timeStr = getTimeStr() timeStr = getTimeStr()
cKey = cKey =
encryptor.encrypt(cnlid, timeStr, appVer, guid, platform) encryptor!!.encrypt(cnlid, timeStr, appVer, guid, platform)
signature = getSignature() signature = getSignature()
return """{"cnlid":"$cnlid","livepid":"$livepid","stream":"$stream","guid":"$guid","cKey":"$cKey","adjust":$adjust,"sphttps":"$sphttps","platform":"$platform","cmd":"$cmd","encryptVer":"$encryptVer","dtype":"$dtype","devid":"$devid","otype":"$otype","appVer":"$appVer","app_version":"$appVersion","rand_str":"$randStr","channel":"$channel","defn":"$defn","signature":"$signature"}""" return """{"cnlid":"$cnlid","livepid":"$livepid","stream":"$stream","guid":"$guid","cKey":"$cKey","adjust":$adjust,"sphttps":"$sphttps","platform":"$platform","cmd":"$cmd","encryptVer":"$encryptVer","dtype":"$dtype","devid":"$devid","otype":"$otype","appVer":"$appVer","app_version":"$appVersion","rand_str":"$randStr","channel":"$channel","defn":"$defn","signature":"$signature"}"""
} }
@@ -105,17 +110,23 @@ object YSP {
} }
fun getGuid(): String { fun getGuid(): String {
var guid = SP.guid var guid = sharedPref.getString("guid", "")
if (guid.length < 18) { if (guid == null || guid.length < 18) {
guid = generateGuid() guid = generateGuid()
SP.guid = guid with(sharedPref.edit()) {
putString("guid", guid)
apply()
}
} }
return guid return guid
} }
private fun newGuid(): String { private fun newGuid(): String {
guid = generateGuid() guid = generateGuid()
SP.guid = guid with(sharedPref.edit()) {
putString("guid", guid)
apply()
}
return guid return guid
} }
@@ -132,14 +143,18 @@ object YSP {
private fun getSignature(): String { private fun getSignature(): String {
val e = val e =
"adjust=${adjust}&appVer=${appVer}&app_version=$appVersion&cKey=$cKey&channel=$channel&cmd=$cmd&cnlid=$cnlid&defn=${defn}&devid=${devid}&dtype=${dtype}&encryptVer=${encryptVer}&guid=${guid}&livepid=${livepid}&otype=${otype}&platform=${platform}&rand_str=${randStr}&sphttps=${sphttps}&stream=${stream}".toByteArray() "adjust=${adjust}&appVer=${appVer}&app_version=$appVersion&cKey=$cKey&channel=$channel&cmd=$cmd&cnlid=$cnlid&defn=${defn}&devid=${devid}&dtype=${dtype}&encryptVer=${encryptVer}&guid=${guid}&livepid=${livepid}&otype=${otype}&platform=${platform}&rand_str=${randStr}&sphttps=${sphttps}&stream=${stream}".toByteArray()
val hashedData = encryptor.hash(e) ?: return "" val hashedData = encryptor?.hash(e) ?: return ""
return hashedData.let { it -> it.joinToString("") { "%02x".format(it) } } return hashedData.let { it -> it.joinToString("") { "%02x".format(it) } }
} }
private fun getAuthSignature(): String { private fun getAuthSignature(): String {
val e = val e =
"appid=${appid}&guid=${guid}&pid=${livepid}&rand_str=${randStr}".toByteArray() "appid=${appid}&guid=${guid}&pid=${livepid}&rand_str=${randStr}".toByteArray()
val hashedData = encryptor.hash2(e) ?: return "" val hashedData = encryptor?.hash2(e) ?: return ""
return hashedData.let { it -> it.joinToString("") { "%02x".format(it) } } return hashedData.let { it -> it.joinToString("") { "%02x".format(it) } }
} }
companion object {
private const val TAG = "YSP"
}
} }
@@ -10,13 +10,4 @@ interface YSPTokenService {
fun getInfo( fun getInfo(
@Query("token") token: String = "", @Query("token") token: String = "",
): Call<Info> ): Call<Info>
@GET("my-tv/v2/token")
fun getToken(
@Query("token") token: String = "",
): Call<Token>
@GET("my-tv/v2/info")
fun getInfoV2(
): Call<InfoV2>
} }
Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

+25
View File
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/row"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/row_header"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start"
android:layout_marginTop="0dp"
android:layout_marginStart="10dp"
android:layout_marginBottom="5dp"
android:gravity="start"
android:textColor="#FFEEEEEE"
android:textSize="22sp" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/row_items"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</androidx.recyclerview.widget.RecyclerView>
</LinearLayout>
+17
View File
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/show_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ScrollView
android:id="@+id/scroll_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
</LinearLayout>
</ScrollView>
</FrameLayout>
+62 -62
View File
@@ -2,7 +2,7 @@
{ {
"id": 0, "id": 0,
"videoIndex": 0, "videoIndex": 0,
"channel": "央视", "channel": "央视频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202306/d57905b93540bd15f0c48230dbbbff7ee0d645ff539e38866e2d15c8b9f7dfcd.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/d57905b93540bd15f0c48230dbbbff7ee0d645ff539e38866e2d15c8b9f7dfcd.png?imageMogr2/format/webp",
"pid": "600001859", "pid": "600001859",
"sid": "2000210103", "sid": "2000210103",
@@ -17,7 +17,7 @@
{ {
"id": 1, "id": 1,
"videoIndex": 0, "videoIndex": 0,
"channel": "央视", "channel": "央视频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202306/20115388de0207131af17eac86c33049b95d69eaff064e55653a1b941810a006.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/20115388de0207131af17eac86c33049b95d69eaff064e55653a1b941810a006.png?imageMogr2/format/webp",
"pid": "600001800", "pid": "600001800",
"sid": "2000203603", "sid": "2000203603",
@@ -32,7 +32,7 @@
{ {
"id": 2, "id": 2,
"videoIndex": 0, "videoIndex": 0,
"channel": "央视", "channel": "央视频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202306/7b7a65c712450da3deb6ca66fbacf4f9aee00d3f20bd80eafb5ada01ec63eb3a.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/7b7a65c712450da3deb6ca66fbacf4f9aee00d3f20bd80eafb5ada01ec63eb3a.png?imageMogr2/format/webp",
"pid": "600001801", "pid": "600001801",
"sid": "2000203803", "sid": "2000203803",
@@ -47,7 +47,7 @@
{ {
"id": 3, "id": 3,
"videoIndex": 0, "videoIndex": 0,
"channel": "央视", "channel": "央视频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202306/f357e58fdbcc076a3d65e1f958c942b2e14f14342c60736ceed98b092d35356a.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/f357e58fdbcc076a3d65e1f958c942b2e14f14342c60736ceed98b092d35356a.png?imageMogr2/format/webp",
"pid": "600001814", "pid": "600001814",
"sid": "2000204803", "sid": "2000204803",
@@ -63,7 +63,7 @@
{ {
"id": 4, "id": 4,
"videoIndex": 0, "videoIndex": 0,
"channel": "央视", "channel": "央视频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202306/0a6a7138952675983a3d854df7688557b286d59aa06166edae51506f9204d655.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/0a6a7138952675983a3d854df7688557b286d59aa06166edae51506f9204d655.png?imageMogr2/format/webp",
"pid": "600001818", "pid": "600001818",
"sid": "2000205103", "sid": "2000205103",
@@ -78,7 +78,7 @@
{ {
"id": 5, "id": 5,
"videoIndex": 0, "videoIndex": 0,
"channel": "央视", "channel": "央视频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202306/741515efda91f03f455df8a7da4ee11fa9329139c276435cf0a9e2af398d5bf2.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/741515efda91f03f455df8a7da4ee11fa9329139c276435cf0a9e2af398d5bf2.png?imageMogr2/format/webp",
"pid": "600001802", "pid": "600001802",
"sid": "2013693901", "sid": "2013693901",
@@ -93,7 +93,7 @@
{ {
"id": 6, "id": 6,
"videoIndex": 0, "videoIndex": 0,
"channel": "央视", "channel": "央视频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202306/b29af94e295ebdf646cefb68122c429b9cd921f498ca20d2d8070252536f9ff9.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/b29af94e295ebdf646cefb68122c429b9cd921f498ca20d2d8070252536f9ff9.png?imageMogr2/format/webp",
"pid": "600004092", "pid": "600004092",
"sid": "2000510003", "sid": "2000510003",
@@ -108,7 +108,7 @@
{ {
"id": 7, "id": 7,
"videoIndex": 0, "videoIndex": 0,
"channel": "央视", "channel": "央视频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202306/ad51de94426a0ba039e6dd6a8534ea98ecc813a6176bde87b4f18cc34d6d7590.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/ad51de94426a0ba039e6dd6a8534ea98ecc813a6176bde87b4f18cc34d6d7590.png?imageMogr2/format/webp",
"pid": "600001803", "pid": "600001803",
"sid": "2000203903", "sid": "2000203903",
@@ -123,7 +123,7 @@
{ {
"id": 8, "id": 8,
"videoIndex": 0, "videoIndex": 0,
"channel": "央视", "channel": "央视频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202306/2ed1b4deeca179d5db806bb941790f82eb92a1b7299c1c38fe027f95a5caee5e.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/2ed1b4deeca179d5db806bb941790f82eb92a1b7299c1c38fe027f95a5caee5e.png?imageMogr2/format/webp",
"pid": "600004078", "pid": "600004078",
"sid": "2000499403", "sid": "2000499403",
@@ -138,7 +138,7 @@
{ {
"id": 9, "id": 9,
"videoIndex": 0, "videoIndex": 0,
"channel": "央视", "channel": "央视频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202306/aa6157ec65188cd41826e5a2f088c3d6d153205f5f6428258d12c59999e221aa.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/aa6157ec65188cd41826e5a2f088c3d6d153205f5f6428258d12c59999e221aa.png?imageMogr2/format/webp",
"pid": "600001805", "pid": "600001805",
"sid": "2000203503", "sid": "2000203503",
@@ -153,7 +153,7 @@
{ {
"id": 10, "id": 10,
"videoIndex": 0, "videoIndex": 0,
"channel": "央视", "channel": "央视频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202306/ed12ed7c7a1034dae4350011fe039284c5d5a836506b28c9e32e3c75299625c0.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/ed12ed7c7a1034dae4350011fe039284c5d5a836506b28c9e32e3c75299625c0.png?imageMogr2/format/webp",
"pid": "600001806", "pid": "600001806",
"sid": "2000204103", "sid": "2000204103",
@@ -168,7 +168,7 @@
{ {
"id": 11, "id": 11,
"videoIndex": 0, "videoIndex": 0,
"channel": "央视", "channel": "央视频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202306/484083cffaa40df7e659565e8cb4d1cc740158a185512114167aa21fa0c59240.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/484083cffaa40df7e659565e8cb4d1cc740158a185512114167aa21fa0c59240.png?imageMogr2/format/webp",
"pid": "600001807", "pid": "600001807",
"sid": "2000202603", "sid": "2000202603",
@@ -183,7 +183,7 @@
{ {
"id": 12, "id": 12,
"videoIndex": 0, "videoIndex": 0,
"channel": "央视", "channel": "央视频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202306/266da7b43c03e2312186b4a999e0f060e8f15b10d2cc2c9aa32171819254cf1a.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/266da7b43c03e2312186b4a999e0f060e8f15b10d2cc2c9aa32171819254cf1a.png?imageMogr2/format/webp",
"pid": "600001811", "pid": "600001811",
"sid": "2000204603", "sid": "2000204603",
@@ -199,7 +199,7 @@
{ {
"id": 13, "id": 13,
"videoIndex": 0, "videoIndex": 0,
"channel": "央视", "channel": "央视频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202306/af6b603896938dc346fbb16abfc63c12cba54b0ec9d18770a15d347d115f12d5.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/af6b603896938dc346fbb16abfc63c12cba54b0ec9d18770a15d347d115f12d5.png?imageMogr2/format/webp",
"pid": "600001809", "pid": "600001809",
"sid": "2000204403", "sid": "2000204403",
@@ -214,7 +214,7 @@
{ {
"id": 14, "id": 14,
"videoIndex": 0, "videoIndex": 0,
"channel": "央视", "channel": "央视频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202306/2ceee92188ef684efe0d8b90839c4f3ad450d179dc64d59beff417059453af47.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/2ceee92188ef684efe0d8b90839c4f3ad450d179dc64d59beff417059453af47.png?imageMogr2/format/webp",
"pid": "600001815", "pid": "600001815",
"sid": "2000205003", "sid": "2000205003",
@@ -229,7 +229,7 @@
{ {
"id": 15, "id": 15,
"videoIndex": 0, "videoIndex": 0,
"channel": "央视", "channel": "央视频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202306/53793fa7bacd3a93ff6dc5d2758418985e1f952a316c335d663b572d8bdcd74d.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/53793fa7bacd3a93ff6dc5d2758418985e1f952a316c335d663b572d8bdcd74d.png?imageMogr2/format/webp",
"pid": "600098637", "pid": "600098637",
"sid": "2012375003", "sid": "2012375003",
@@ -245,7 +245,7 @@
{ {
"id": 16, "id": 16,
"videoIndex": 0, "videoIndex": 0,
"channel": "央视", "channel": "央视频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202306/ddef563072f8bad2bea5b9e52674cb7b4ed50efb20c26e61994dfbdf05c1e3c0.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/ddef563072f8bad2bea5b9e52674cb7b4ed50efb20c26e61994dfbdf05c1e3c0.png?imageMogr2/format/webp",
"pid": "600001810", "pid": "600001810",
"sid": "2000204203", "sid": "2000204203",
@@ -260,7 +260,7 @@
{ {
"id": 17, "id": 17,
"videoIndex": 0, "videoIndex": 0,
"channel": "央视", "channel": "央视频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202306/649ad76a90bfef55b05db9fe52e006487280f619089099d5dc971e387fc6eff0.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/649ad76a90bfef55b05db9fe52e006487280f619089099d5dc971e387fc6eff0.png?imageMogr2/format/webp",
"pid": "600001817", "pid": "600001817",
"sid": "2000204503", "sid": "2000204503",
@@ -275,7 +275,7 @@
{ {
"id": 18, "id": 18,
"videoIndex": 0, "videoIndex": 0,
"channel": "央视", "channel": "央视频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202306/3e9d06fd7244d950df5838750f1c6ac3456e172b51caca2c16d2282125b111e8.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/3e9d06fd7244d950df5838750f1c6ac3456e172b51caca2c16d2282125b111e8.png?imageMogr2/format/webp",
"pid": "600002264", "pid": "600002264",
"sid": "2000266303", "sid": "2000266303",
@@ -290,7 +290,7 @@
{ {
"id": 19, "id": 19,
"videoIndex": 0, "videoIndex": 0,
"channel": "央视", "channel": "央视频道",
"logo": "", "logo": "",
"pid": "600156816", "pid": "600156816",
"sid": "2020603421", "sid": "2020603421",
@@ -305,7 +305,7 @@
{ {
"id": 20, "id": 20,
"videoIndex": 0, "videoIndex": 0,
"channel": "央视", "channel": "央视频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202306/4d549e53e6d0f632d5a633d1945280797b153e588f919221a07faa869812cc89.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/4d549e53e6d0f632d5a633d1945280797b153e588f919221a07faa869812cc89.png?imageMogr2/format/webp",
"pid": "600099658", "pid": "600099658",
"sid": "2012513603", "sid": "2012513603",
@@ -320,7 +320,7 @@
{ {
"id": 21, "id": 21,
"videoIndex": 0, "videoIndex": 0,
"channel": "央视", "channel": "央视频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202306/a556bd7d93ce65e18f243a8892b5604f4faa994a4897315914216a710a706208.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/a556bd7d93ce65e18f243a8892b5604f4faa994a4897315914216a710a706208.png?imageMogr2/format/webp",
"pid": "600099655", "pid": "600099655",
"sid": "2012514403", "sid": "2012514403",
@@ -335,7 +335,7 @@
{ {
"id": 22, "id": 22,
"videoIndex": 0, "videoIndex": 0,
"channel": "央视", "channel": "央视频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202306/5661bd04fecdb6e899f801147a22ab5d3a475bf2b62e30aec2c0023190ebc9b1.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/5661bd04fecdb6e899f801147a22ab5d3a475bf2b62e30aec2c0023190ebc9b1.png?imageMogr2/format/webp",
"pid": "600099620", "pid": "600099620",
"sid": "2012511203", "sid": "2012511203",
@@ -350,7 +350,7 @@
{ {
"id": 23, "id": 23,
"videoIndex": 0, "videoIndex": 0,
"channel": "央视", "channel": "央视频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202306/bb3c6c9e145d698137f5bb64a582021a01b51344b929003630eb769ea65832a9.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/bb3c6c9e145d698137f5bb64a582021a01b51344b929003630eb769ea65832a9.png?imageMogr2/format/webp",
"pid": "600099637", "pid": "600099637",
"sid": "2012513303", "sid": "2012513303",
@@ -365,7 +365,7 @@
{ {
"id": 24, "id": 24,
"videoIndex": 0, "videoIndex": 0,
"channel": "央视", "channel": "央视频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202306/bbf1d024c5228b8dd128b0e3cb1717d173fab4ee84c3a4c8a57b1a215362ca3b.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/bbf1d024c5228b8dd128b0e3cb1717d173fab4ee84c3a4c8a57b1a215362ca3b.png?imageMogr2/format/webp",
"pid": "600099660", "pid": "600099660",
"sid": "2012514103", "sid": "2012514103",
@@ -380,7 +380,7 @@
{ {
"id": 25, "id": 25,
"videoIndex": 0, "videoIndex": 0,
"channel": "央视", "channel": "央视频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202306/4c6b6a6d3839889f34d33db3c2f80233b26b74d3489b393487635f8704e70796.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/4c6b6a6d3839889f34d33db3c2f80233b26b74d3489b393487635f8704e70796.png?imageMogr2/format/webp",
"pid": "600099649", "pid": "600099649",
"sid": "2012513403", "sid": "2012513403",
@@ -395,7 +395,7 @@
{ {
"id": 26, "id": 26,
"videoIndex": 0, "videoIndex": 0,
"channel": "央视", "channel": "央视频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202306/cd1e2bb52b06a991de168733e5ff0f1d85adc8042d40c8f393f723543e5dd08a.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/cd1e2bb52b06a991de168733e5ff0f1d85adc8042d40c8f393f723543e5dd08a.png?imageMogr2/format/webp",
"pid": "600099636", "pid": "600099636",
"sid": "2012514203", "sid": "2012514203",
@@ -410,7 +410,7 @@
{ {
"id": 27, "id": 27,
"videoIndex": 0, "videoIndex": 0,
"channel": "央视", "channel": "央视频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202306/cdd1b31ede7a5ad049ed53d9a072422f829e72dd062ed2c19e077fdd01699071.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/cdd1b31ede7a5ad049ed53d9a072422f829e72dd062ed2c19e077fdd01699071.png?imageMogr2/format/webp",
"pid": "600099659", "pid": "600099659",
"sid": "2012512503", "sid": "2012512503",
@@ -425,7 +425,7 @@
{ {
"id": 28, "id": 28,
"videoIndex": 0, "videoIndex": 0,
"channel": "央视", "channel": "央视频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202306/fa28955ce8b2539d728bf4c6a13a46ff57ad76eae46627f7bcfb1ed8a613d3fc.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/fa28955ce8b2539d728bf4c6a13a46ff57ad76eae46627f7bcfb1ed8a613d3fc.png?imageMogr2/format/webp",
"pid": "600099650", "pid": "600099650",
"sid": "2012513903", "sid": "2012513903",
@@ -440,7 +440,7 @@
{ {
"id": 29, "id": 29,
"videoIndex": 0, "videoIndex": 0,
"channel": "央视", "channel": "央视频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202306/14ac5ce40482cacd3d4b37435222bfe86af2b452a2f04ecbfc1d13d76edd7c57.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/14ac5ce40482cacd3d4b37435222bfe86af2b452a2f04ecbfc1d13d76edd7c57.png?imageMogr2/format/webp",
"pid": "600099653", "pid": "600099653",
"sid": "2012513803", "sid": "2012513803",
@@ -455,7 +455,7 @@
{ {
"id": 30, "id": 30,
"videoIndex": 0, "videoIndex": 0,
"channel": "央视", "channel": "央视频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202306/10e14a92478011aa6c3c8562e62127f3b1908e29fcd78e4b2b24b9e6d3ec2fbc.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/10e14a92478011aa6c3c8562e62127f3b1908e29fcd78e4b2b24b9e6d3ec2fbc.png?imageMogr2/format/webp",
"pid": "600099652", "pid": "600099652",
"sid": "2012513703", "sid": "2012513703",
@@ -470,7 +470,7 @@
{ {
"id": 31, "id": 31,
"videoIndex": 0, "videoIndex": 0,
"channel": "央视", "channel": "央视频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202306/244d72c0eb1615ed7d51c2f5db5a67f306aa3f58c05bc2d34de3aa7e956dc8c9.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/244d72c0eb1615ed7d51c2f5db5a67f306aa3f58c05bc2d34de3aa7e956dc8c9.png?imageMogr2/format/webp",
"pid": "600099656", "pid": "600099656",
"sid": "2012514003", "sid": "2012514003",
@@ -485,7 +485,7 @@
{ {
"id": 32, "id": 32,
"videoIndex": 0, "videoIndex": 0,
"channel": "央视", "channel": "央视频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202306/54a6863656fdfd8f803be193ddf22441c5000a108833889816fd2d8911715ce8.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/54a6863656fdfd8f803be193ddf22441c5000a108833889816fd2d8911715ce8.png?imageMogr2/format/webp",
"pid": "600099651", "pid": "600099651",
"sid": "2012513503", "sid": "2012513503",
@@ -500,7 +500,7 @@
{ {
"id": 33, "id": 33,
"videoIndex": 0, "videoIndex": 0,
"channel": "地方", "channel": "地方频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202306/9bd372ca292a82ce3aa08772b07efc4af1f85c21d1f268ea33440c49e9a0a488.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/9bd372ca292a82ce3aa08772b07efc4af1f85c21d1f268ea33440c49e9a0a488.png?imageMogr2/format/webp",
"pid": "600002483", "pid": "600002483",
"sid": "2000292403", "sid": "2000292403",
@@ -515,7 +515,7 @@
{ {
"id": 34, "id": 34,
"videoIndex": 0, "videoIndex": 0,
"channel": "地方", "channel": "地方频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202306/4120e89d3079d08aa17d382f69a2308ec70839b278367763c34a34666c75cb88.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/4120e89d3079d08aa17d382f69a2308ec70839b278367763c34a34666c75cb88.png?imageMogr2/format/webp",
"pid": "600002475", "pid": "600002475",
"sid": "2000296203", "sid": "2000296203",
@@ -531,7 +531,7 @@
{ {
"id": 35, "id": 35,
"videoIndex": 0, "videoIndex": 0,
"channel": "地方", "channel": "地方频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202306/7a6be5a2bb1dc53a945c016ff1f525dc4a84c51db371c15c89aa55404b0ba784.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/7a6be5a2bb1dc53a945c016ff1f525dc4a84c51db371c15c89aa55404b0ba784.png?imageMogr2/format/webp",
"pid": "600002508", "pid": "600002508",
"sid": "2000294503", "sid": "2000294503",
@@ -547,7 +547,7 @@
{ {
"id": 36, "id": 36,
"videoIndex": 0, "videoIndex": 0,
"channel": "地方", "channel": "地方频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202306/ac4ed6058a87c101ae7147ebc38905d0cae047fb73fd277ee5049b84f52bda36.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/ac4ed6058a87c101ae7147ebc38905d0cae047fb73fd277ee5049b84f52bda36.png?imageMogr2/format/webp",
"pid": "600002505", "pid": "600002505",
"sid": "2000281303", "sid": "2000281303",
@@ -563,7 +563,7 @@
{ {
"id": 37, "id": 37,
"videoIndex": 0, "videoIndex": 0,
"channel": "地方", "channel": "地方频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202306/380ad685c0c1d5b2c902246b8d2df6d3f9b45e2837abcfe493075bbded597a31.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/380ad685c0c1d5b2c902246b8d2df6d3f9b45e2837abcfe493075bbded597a31.png?imageMogr2/format/webp",
"pid": "600002521", "pid": "600002521",
"sid": "2000295603", "sid": "2000295603",
@@ -579,7 +579,7 @@
{ {
"id": 38, "id": 38,
"videoIndex": 0, "videoIndex": 0,
"channel": "地方", "channel": "地方频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202306/3c760d0d00463855890e8a1864ea4a6b6dd66b90c29b4ac714a4b17c16519871.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/3c760d0d00463855890e8a1864ea4a6b6dd66b90c29b4ac714a4b17c16519871.png?imageMogr2/format/webp",
"pid": "600002503", "pid": "600002503",
"sid": "2000294103", "sid": "2000294103",
@@ -595,7 +595,7 @@
{ {
"id": 39, "id": 39,
"videoIndex": 0, "videoIndex": 0,
"channel": "地方", "channel": "地方频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202306/22d403f07a7cf5410b3ad3ddb65a11aa229a32475fac213f5344c9f0ec330ca1.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/22d403f07a7cf5410b3ad3ddb65a11aa229a32475fac213f5344c9f0ec330ca1.png?imageMogr2/format/webp",
"pid": "600002513", "pid": "600002513",
"sid": "2000294803", "sid": "2000294803",
@@ -610,7 +610,7 @@
{ {
"id": 40, "id": 40,
"videoIndex": 0, "videoIndex": 0,
"channel": "地方", "channel": "地方频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202306/28886880a4dc0f06fb7e0a528a1def0591d61a65870e29176ede0cc92033bbfd.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/28886880a4dc0f06fb7e0a528a1def0591d61a65870e29176ede0cc92033bbfd.png?imageMogr2/format/webp",
"pid": "600002485", "pid": "600002485",
"sid": "2000292703", "sid": "2000292703",
@@ -625,7 +625,7 @@
{ {
"id": 41, "id": 41,
"videoIndex": 0, "videoIndex": 0,
"channel": "地方", "channel": "地方频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202306/54b7e97cb816bb223fe05f3fc44da2c7820eb66e8550c19d23100f2c414ecc38.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/54b7e97cb816bb223fe05f3fc44da2c7820eb66e8550c19d23100f2c414ecc38.png?imageMogr2/format/webp",
"pid": "600002509", "pid": "600002509",
"sid": "2000294203", "sid": "2000294203",
@@ -641,7 +641,7 @@
{ {
"id": 42, "id": 42,
"videoIndex": 0, "videoIndex": 0,
"channel": "地方", "channel": "地方频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202306/657651f411de2673d1770d9a78b44c1265704f7468cc41d4be7f51d630768494.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/657651f411de2673d1770d9a78b44c1265704f7468cc41d4be7f51d630768494.png?imageMogr2/format/webp",
"pid": "600002531", "pid": "600002531",
"sid": "2000297803", "sid": "2000297803",
@@ -657,7 +657,7 @@
{ {
"id": 43, "id": 43,
"videoIndex": 0, "videoIndex": 0,
"channel": "地方", "channel": "地方频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202306/74925962148a6d31c85808b6cd4e444c2a54bab393d2c5fc85e960b50e22fa86.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/74925962148a6d31c85808b6cd4e444c2a54bab393d2c5fc85e960b50e22fa86.png?imageMogr2/format/webp",
"pid": "600002525", "pid": "600002525",
"sid": "2000296103", "sid": "2000296103",
@@ -673,7 +673,7 @@
{ {
"id": 44, "id": 44,
"videoIndex": 0, "videoIndex": 0,
"channel": "地方", "channel": "地方频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202306/d545becdc81c60197b08c7f47380705e4665ed3fe55efc8b855e486f6e655378.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/d545becdc81c60197b08c7f47380705e4665ed3fe55efc8b855e486f6e655378.png?imageMogr2/format/webp",
"pid": "600002493", "pid": "600002493",
"sid": "2000293403", "sid": "2000293403",
@@ -689,7 +689,7 @@
{ {
"id": 45, "id": 45,
"videoIndex": 0, "videoIndex": 0,
"channel": "地方", "channel": "地方频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202306/4eb45f4781d33d872af027dc01c941559aab55667dd99cc5c22bef7037807b13.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/4eb45f4781d33d872af027dc01c941559aab55667dd99cc5c22bef7037807b13.png?imageMogr2/format/webp",
"pid": "600002490", "pid": "600002490",
"sid": "2000293303", "sid": "2000293303",
@@ -705,7 +705,7 @@
{ {
"id": 46, "id": 46,
"videoIndex": 0, "videoIndex": 0,
"channel": "地方", "channel": "地方频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202306/f4f23633c578beea49a3841d88d3490100f029ee349059fa532869db889872c5.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/f4f23633c578beea49a3841d88d3490100f029ee349059fa532869db889872c5.png?imageMogr2/format/webp",
"pid": "600002309", "pid": "600002309",
"sid": "2000272103", "sid": "2000272103",
@@ -721,7 +721,7 @@
{ {
"id": 47, "id": 47,
"videoIndex": 0, "videoIndex": 0,
"channel": "地方", "channel": "地方频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202306/d8273ae9be698ce2db21f5b886ecac95a73429593f93713c60ed8c12c38bf0d3.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/d8273ae9be698ce2db21f5b886ecac95a73429593f93713c60ed8c12c38bf0d3.png?imageMogr2/format/webp",
"pid": "600002498", "pid": "600002498",
"sid": "2000293903", "sid": "2000293903",
@@ -737,7 +737,7 @@
{ {
"id": 48, "id": 48,
"videoIndex": 0, "videoIndex": 0,
"channel": "地方", "channel": "地方频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202306/a66c836bd98ba3e41a2e9a570d4b9c50dedc6839e9de333e2e78212ad505f37e.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/a66c836bd98ba3e41a2e9a570d4b9c50dedc6839e9de333e2e78212ad505f37e.png?imageMogr2/format/webp",
"pid": "600002520", "pid": "600002520",
"sid": "2000295503", "sid": "2000295503",
@@ -753,7 +753,7 @@
{ {
"id": 49, "id": 49,
"videoIndex": 0, "videoIndex": 0,
"channel": "地方", "channel": "地方频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202306/f35fa04b51b1ee4984b03578b65403570868ebca03c6c01e11b097f999a58d9b.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/f35fa04b51b1ee4984b03578b65403570868ebca03c6c01e11b097f999a58d9b.png?imageMogr2/format/webp",
"pid": "600002532", "pid": "600002532",
"sid": "2000298003", "sid": "2000298003",
@@ -769,7 +769,7 @@
{ {
"id": 50, "id": 50,
"videoIndex": 0, "videoIndex": 0,
"channel": "地方", "channel": "地方频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202306/d59fec04c902e3581c617136d02d4b9b8c4cbe64272781ddd3525e80c823edb7.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/d59fec04c902e3581c617136d02d4b9b8c4cbe64272781ddd3525e80c823edb7.png?imageMogr2/format/webp",
"pid": "600002481", "pid": "600002481",
"sid": "2000292203", "sid": "2000292203",
@@ -785,7 +785,7 @@
{ {
"id": 51, "id": 51,
"videoIndex": 0, "videoIndex": 0,
"channel": "地方", "channel": "地方频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202306/3276a414ae0eaa0f116f2045cd913367967d0c7c1e978e8621ac3879436c6ed7.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/3276a414ae0eaa0f116f2045cd913367967d0c7c1e978e8621ac3879436c6ed7.png?imageMogr2/format/webp",
"pid": "600002516", "pid": "600002516",
"sid": "2000295003", "sid": "2000295003",
@@ -801,7 +801,7 @@
{ {
"id": 52, "id": 52,
"videoIndex": 0, "videoIndex": 0,
"channel": "地方", "channel": "地方频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202306/3208fe6564a293c21b711333fb3edb05bb5b406cff840573c9a8d839680a1579.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/3208fe6564a293c21b711333fb3edb05bb5b406cff840573c9a8d839680a1579.png?imageMogr2/format/webp",
"pid": "600002484", "pid": "600002484",
"sid": "2000292503", "sid": "2000292503",
@@ -817,7 +817,7 @@
{ {
"id": 53, "id": 53,
"videoIndex": 0, "videoIndex": 0,
"channel": "地方", "channel": "地方频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202306/6e060391fde0469801fc3d84dbf204b4f8d650d251f17d7595a6964c0bb99e81.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/6e060391fde0469801fc3d84dbf204b4f8d650d251f17d7595a6964c0bb99e81.png?imageMogr2/format/webp",
"pid": "600002506", "pid": "600002506",
"sid": "2000291503", "sid": "2000291503",
@@ -833,7 +833,7 @@
{ {
"id": 54, "id": 54,
"videoIndex": 0, "videoIndex": 0,
"channel": "地方", "channel": "地方频道",
"logo": "", "logo": "",
"pid": "600152137", "pid": "600152137",
"sid": "2019927003", "sid": "2019927003",
@@ -848,7 +848,7 @@
{ {
"id": 55, "id": 55,
"videoIndex": 0, "videoIndex": 0,
"channel": "地方", "channel": "地方频道",
"logo": "", "logo": "",
"pid": "600152138", "pid": "600152138",
"sid": "2019927403", "sid": "2019927403",
@@ -863,7 +863,7 @@
{ {
"id": 56, "id": 56,
"videoIndex": 0, "videoIndex": 0,
"channel": "国际", "channel": "国际频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202306/a72dff758ca1c17cd0ecc8cedc11b893d208f409d5e6302faa0e9d298848abc3.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/a72dff758ca1c17cd0ecc8cedc11b893d208f409d5e6302faa0e9d298848abc3.png?imageMogr2/format/webp",
"pid": "600014550", "pid": "600014550",
"sid": "2001656803", "sid": "2001656803",
@@ -878,7 +878,7 @@
{ {
"id": 57, "id": 57,
"videoIndex": 0, "videoIndex": 0,
"channel": "国际", "channel": "国际频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202306/a8d0046a47433d952bf6ed17062deb8bd2184ba9aec0f7781df6bf9487a3ffcf.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/a8d0046a47433d952bf6ed17062deb8bd2184ba9aec0f7781df6bf9487a3ffcf.png?imageMogr2/format/webp",
"pid": "600084704", "pid": "600084704",
"sid": "2010153503", "sid": "2010153503",
@@ -893,7 +893,7 @@
{ {
"id": 58, "id": 58,
"videoIndex": 0, "videoIndex": 0,
"channel": "国际", "channel": "国际频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202306/bf0a820893cbaf20dd0333e27042e1ef9c8806e5b602b6a8c95af399db0bc77a.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/bf0a820893cbaf20dd0333e27042e1ef9c8806e5b602b6a8c95af399db0bc77a.png?imageMogr2/format/webp",
"pid": "600084758", "pid": "600084758",
"sid": "2010152603", "sid": "2010152603",
@@ -908,7 +908,7 @@
{ {
"id": 59, "id": 59,
"videoIndex": 0, "videoIndex": 0,
"channel": "国际", "channel": "国际频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202306/2e44e2aa3e7a1cedf07fd0ae59fe69e86a60a2632660a006e3e9e7397b2d107e.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/2e44e2aa3e7a1cedf07fd0ae59fe69e86a60a2632660a006e3e9e7397b2d107e.png?imageMogr2/format/webp",
"pid": "600084782", "pid": "600084782",
"sid": "2010155203", "sid": "2010155203",
@@ -923,7 +923,7 @@
{ {
"id": 60, "id": 60,
"videoIndex": 0, "videoIndex": 0,
"channel": "国际", "channel": "国际频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202309/7c337e3dbe64402ec7e4678a619a4a6d95144e42f35161181ff78e143b7cf67a.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202309/7c337e3dbe64402ec7e4678a619a4a6d95144e42f35161181ff78e143b7cf67a.png?imageMogr2/format/webp",
"pid": "600084744", "pid": "600084744",
"sid": "2010152503", "sid": "2010152503",
@@ -939,7 +939,7 @@
{ {
"id": 61, "id": 61,
"videoIndex": 0, "videoIndex": 0,
"channel": "国际", "channel": "国际频道",
"logo": "https://resources.yangshipin.cn/assets/oms/image/202309/74d3ac436a7e374879578de1d87a941fbf566d39d5632b027c5097891ed32bd5.png?imageMogr2/format/webp", "logo": "https://resources.yangshipin.cn/assets/oms/image/202309/74d3ac436a7e374879578de1d87a941fbf566d39d5632b027c5097891ed32bd5.png?imageMogr2/format/webp",
"pid": "600084781", "pid": "600084781",
"sid": "2010155403", "sid": "2010155403",
+1
View File
@@ -2,4 +2,5 @@
<color name="fastlane_background">#30000000</color> <color name="fastlane_background">#30000000</color>
<color name="black">#000</color> <color name="black">#000</color>
<color name="white">#FFF</color> <color name="white">#FFF</color>
<color name="gray_overlay">#7F000000</color>
</resources> </resources>
+2 -4
View File
@@ -1,6 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<integer name="local_channel_version">1</integer> <string name="server_url">http://localhost:8080</string>
<string name="server_version_url">https://fastly.jsdelivr.net/gh/LeGend-wLw/my-tv-json-utils@main/version.txt</string> </resources>
<string name="server_url">https://fastly.jsdelivr.net/gh/LeGend-wLw/my-tv-json-utils@main/channels.json</string>
</resources>
+16 -1
View File
@@ -1,10 +1,25 @@
<resources> <resources>
<style name="CustomImageCardViewStyle" parent="Widget.Leanback.ImageCardViewStyle"> <style name="CustomImageCardViewStyle" parent="Widget.Leanback.ImageCardViewStyle">
<item name="lbImageCardViewType">Title|Content</item> <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">160dp</item>
<item name="android:layout_height">40dp</item>
<item name="android:adjustViewBounds">true</item>
<item name="android:contentDescription">@null</item>
<item name="android:scaleType">centerCrop</item>
<item name="layout_viewType">main</item>
</style> </style>
<style name="CustomImageCardTheme" parent="Theme.Leanback"> <style name="CustomImageCardTheme" parent="Theme.Leanback">
<item name="imageCardViewStyle">@style/CustomImageCardViewStyle</item> <item name="imageCardViewStyle">@style/CustomImageCardViewStyle</item>
<item name="imageCardViewImageStyle">@style/CustomImageCardViewImageStyle</item>
</style> </style>
</resources> </resources>