diff --git a/HISTORY.md b/HISTORY.md
index 39c0483..2008e81 100644
--- a/HISTORY.md
+++ b/HISTORY.md
@@ -1,5 +1,15 @@
## 更新日志
+### v1.7.0(通用)
+
+* 网络请求优化
+
+### v1.6.9(安卓5及以上专用)
+
+* 去掉港澳台和国际频道
+* 解决部分情况下3、6、8等频道无法播放的问题
+* 解决部分情况下启动后黑屏问题
+
### v1.6.8(通用)
* 修复部分设备崩溃的问题
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 3dbaa93..03c65fd 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -7,6 +7,7 @@
android:name="android.software.leanback"
android:required="true" />
+
+
+
+
+
+
- if (!response.isSuccessful) throw java.io.IOException("Unexpected code $response")
- val body = response.body()
- body?.string()?.toInt() ?: 0
- }
- }
- }
-
- /**
- * 获取服务器channel
- *
- * @param url String 服务器地址
- *
- * @return Array 服务器channel
- *
- * @throws java.io.IOException 网络请求失败
- */
- suspend fun getServerChannel(url: String): List {
- 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>() {}.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 本地channel
- */
- suspend fun getLocalChannel(context: Context): List {
- 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>() {}.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) {
- 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()
- }
- }
-}
diff --git a/app/src/main/java/com/lizongying/mytv/ErrorFragment.kt b/app/src/main/java/com/lizongying/mytv/ErrorFragment.kt
new file mode 100644
index 0000000..db094e6
--- /dev/null
+++ b/app/src/main/java/com/lizongying/mytv/ErrorFragment.kt
@@ -0,0 +1,28 @@
+package com.lizongying.mytv
+
+import android.view.View
+import androidx.core.content.ContextCompat
+import androidx.leanback.app.ErrorSupportFragment
+
+class ErrorFragment : ErrorSupportFragment() {
+
+ internal fun setErrorContent(message: String) {
+ imageDrawable =
+ ContextCompat.getDrawable(context!!, androidx.leanback.R.drawable.lb_ic_sad_cloud)
+ this.message = message
+ setDefaultBackground(TRANSLUCENT)
+ backgroundDrawable = ContextCompat.getDrawable(
+ context!!,
+ R.color.black
+ )
+
+ buttonText = resources.getString(R.string.dismiss_error)
+ buttonClickListener = View.OnClickListener {
+ fragmentManager!!.beginTransaction().remove(this@ErrorFragment).commit()
+ }
+ }
+
+ companion object {
+ private const val TRANSLUCENT = false
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/lizongying/mytv/Ext.kt b/app/src/main/java/com/lizongying/mytv/Ext.kt
index 1ba934d..c683554 100644
--- a/app/src/main/java/com/lizongying/mytv/Ext.kt
+++ b/app/src/main/java/com/lizongying/mytv/Ext.kt
@@ -7,6 +7,8 @@ import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.content.pm.Signature
import android.content.pm.SigningInfo
+import android.net.ConnectivityManager
+import android.net.NetworkCapabilities
import android.os.Build
import android.util.Log
import java.security.MessageDigest
@@ -71,6 +73,25 @@ val Context.appSignature: String
return hashSignature(sign)
}
+
+val Context.isNetworkConnected: Boolean
+ get() {
+ val connectivityManager =
+ this.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ val network = connectivityManager.activeNetwork
+ val networkCapabilities = connectivityManager.getNetworkCapabilities(network)
+ return networkCapabilities != null &&
+ (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) ||
+ networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) ||
+ networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET))
+ } else {
+ val networkInfo = connectivityManager.activeNetworkInfo
+ return networkInfo != null && networkInfo.isConnectedOrConnecting
+ }
+ }
+
private fun hashSignature(signature: Signature): String {
return try {
val md = MessageDigest.getInstance("MD5")
diff --git a/app/src/main/java/com/lizongying/mytv/InfoFragment.kt b/app/src/main/java/com/lizongying/mytv/InfoFragment.kt
index 9dcf92d..a41a7ce 100644
--- a/app/src/main/java/com/lizongying/mytv/InfoFragment.kt
+++ b/app/src/main/java/com/lizongying/mytv/InfoFragment.kt
@@ -29,13 +29,13 @@ class InfoFragment : Fragment() {
}
fun show(tvViewModel: TVViewModel) {
- binding.textView.text = tvViewModel.title.value
+ binding.textView.text = tvViewModel.getTV().title
Glide.with(this)
- .load(tvViewModel.logo.value)
+ .load(tvViewModel.getTV().logo)
.into(binding.infoLogo)
- Log.i(TAG, "${tvViewModel.title.value} ${tvViewModel.epg.value}")
+ Log.i(TAG, "${tvViewModel.getTV().title} ${tvViewModel.epg.value}")
val epg = tvViewModel.epg.value?.filter { it.beginTime < Utils.getDateTimestamp() }
if (!epg.isNullOrEmpty()) {
binding.infoDesc.text = epg.last().title
diff --git a/app/src/main/java/com/lizongying/mytv/MainActivity.kt b/app/src/main/java/com/lizongying/mytv/MainActivity.kt
index 97603f0..8099f42 100644
--- a/app/src/main/java/com/lizongying/mytv/MainActivity.kt
+++ b/app/src/main/java/com/lizongying/mytv/MainActivity.kt
@@ -1,5 +1,9 @@
package com.lizongying.mytv
+import android.content.Context
+import android.net.ConnectivityManager
+import android.net.Network
+import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.os.Looper
@@ -7,11 +11,17 @@ import android.util.Log
import android.view.GestureDetector
import android.view.KeyEvent
import android.view.MotionEvent
+import android.view.View
import android.view.View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
import android.view.WindowManager
import android.widget.Toast
import androidx.fragment.app.FragmentActivity
+import androidx.lifecycle.lifecycleScope
import com.lizongying.mytv.models.TVViewModel
+import kotlinx.coroutines.CoroutineStart
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.async
+import kotlinx.coroutines.launch
class MainActivity : FragmentActivity(), Request.RequestListener {
@@ -22,6 +32,7 @@ class MainActivity : FragmentActivity(), Request.RequestListener {
private val infoFragment = InfoFragment()
private val channelFragment = ChannelFragment()
private val settingFragment = SettingFragment()
+ private val errorFragment = ErrorFragment()
private var doubleBackToExitPressedOnce = false
@@ -31,6 +42,16 @@ class MainActivity : FragmentActivity(), Request.RequestListener {
private val delayHideMain: Long = 10000
private val delayHideSetting: Long = 10000
+ init {
+ lifecycleScope.launch(Dispatchers.IO) {
+ val utilsJob = async(start = CoroutineStart.LAZY) { Utils.init() }
+
+ utilsJob.start()
+
+// utilsJob.await()
+ }
+ }
+
override fun onCreate(savedInstanceState: Bundle?) {
Log.i(TAG, "onCreate")
super.onCreate(savedInstanceState)
@@ -50,10 +71,38 @@ class MainActivity : FragmentActivity(), Request.RequestListener {
.add(R.id.main_browse_fragment, infoFragment)
.add(R.id.main_browse_fragment, channelFragment)
.add(R.id.main_browse_fragment, mainFragment)
+// .add(R.id.main_browse_fragment, errorFragment)
.hide(mainFragment)
+// .hide(errorFragment)
.commit()
}
gestureDetector = GestureDetector(this, GestureListener())
+
+ errorFragment.buttonClickListener = View.OnClickListener {
+ supportFragmentManager.beginTransaction()
+ .remove(errorFragment)
+ .commit()
+ }
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ val connectivityManager =
+ getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
+ connectivityManager.registerDefaultNetworkCallback(object :
+ ConnectivityManager.NetworkCallback() {
+ override fun onAvailable(network: Network) {
+ super.onAvailable(network)
+ Log.i(TAG, "net ${Build.VERSION.SDK_INT}")
+ if (this@MainActivity.isNetworkConnected) {
+ Log.i(TAG, "net isNetworkConnected")
+ ready++
+ }
+ }
+ })
+ } else {
+ Log.i(TAG, "net ${Build.VERSION.SDK_INT}")
+ ready++
+ }
+
}
fun showInfoFragment(tvViewModel: TVViewModel) {
@@ -146,11 +195,19 @@ class MainActivity : FragmentActivity(), Request.RequestListener {
fun fragmentReady() {
ready++
Log.i(TAG, "ready $ready")
- if (ready == 5) {
+ if (ready == 6) {
mainFragment.fragmentReady()
}
}
+ fun isPlaying() {
+ if (errorFragment.isVisible) {
+ supportFragmentManager.beginTransaction()
+ .remove(errorFragment)
+ .commit()
+ }
+ }
+
override fun onTouchEvent(event: MotionEvent?): Boolean {
if (event != null) {
gestureDetector.onTouchEvent(event)
@@ -442,7 +499,13 @@ class MainActivity : FragmentActivity(), Request.RequestListener {
Request.onDestroy()
}
- override fun onRequestFinished() {
+ override fun onRequestFinished(message: String?) {
+ if (message != null && !errorFragment.isVisible) {
+ supportFragmentManager.beginTransaction()
+ .add(R.id.main_browse_fragment, errorFragment)
+ .commitNow()
+ errorFragment.setErrorContent(message)
+ }
fragmentReady()
}
diff --git a/app/src/main/java/com/lizongying/mytv/MainFragment.kt b/app/src/main/java/com/lizongying/mytv/MainFragment.kt
index bc7058a..3fca2b7 100644
--- a/app/src/main/java/com/lizongying/mytv/MainFragment.kt
+++ b/app/src/main/java/com/lizongying/mytv/MainFragment.kt
@@ -1,13 +1,12 @@
package com.lizongying.mytv
import android.os.Bundle
-import android.os.Handler
-import android.os.Looper
import android.util.Log
import android.widget.Toast
import androidx.leanback.app.BrowseSupportFragment
import androidx.leanback.widget.ArrayObjectAdapter
import androidx.leanback.widget.HeaderItem
+import androidx.leanback.widget.ImageCardView
import androidx.leanback.widget.ListRow
import androidx.leanback.widget.ListRowPresenter
import androidx.leanback.widget.ListRowPresenter.SelectItemViewHolderTask
@@ -17,7 +16,6 @@ import androidx.leanback.widget.Presenter
import androidx.leanback.widget.Row
import androidx.leanback.widget.RowPresenter
import androidx.lifecycle.lifecycleScope
-import com.lizongying.mytv.Utils.getDateTimestamp
import com.lizongying.mytv.api.YSP
import com.lizongying.mytv.models.TVListViewModel
import com.lizongying.mytv.models.TVViewModel
@@ -57,7 +55,7 @@ class MainFragment : BrowseSupportFragment() {
tvListViewModel.tvListViewModel.value?.forEach { tvViewModel ->
tvViewModel.errInfo.observe(viewLifecycleOwner) { _ ->
if (tvViewModel.errInfo.value != null
- && tvViewModel.id.value == itemPosition
+ && tvViewModel.getTV().id == itemPosition
) {
Toast.makeText(context, tvViewModel.errInfo.value, Toast.LENGTH_SHORT).show()
}
@@ -66,18 +64,18 @@ class MainFragment : BrowseSupportFragment() {
// not first time && channel not change
if (tvViewModel.ready.value != null
- && tvViewModel.id.value == itemPosition
+ && tvViewModel.getTV().id == itemPosition
&& check(tvViewModel)
) {
- Log.i(TAG, "ready ${tvViewModel.title.value}")
+ Log.i(TAG, "ready ${tvViewModel.getTV().title}")
(activity as? MainActivity)?.play(tvViewModel)
}
}
tvViewModel.change.observe(viewLifecycleOwner) { _ ->
if (tvViewModel.change.value != null) {
- val title = tvViewModel.title.value
+ val title = tvViewModel.getTV().title
Log.i(TAG, "switch $title")
- if (tvViewModel.pid.value != "") {
+ if (tvViewModel.getTV().pid != "") {
Log.i(TAG, "request $title")
lifecycleScope.launch(Dispatchers.IO) {
tvViewModel.let { Request.fetchData(it) }
@@ -196,8 +194,8 @@ class MainFragment : BrowseSupportFragment() {
row: Row
) {
if (item is TVViewModel) {
- if (itemPosition != item.id.value!!) {
- itemPosition = item.id.value!!
+ if (itemPosition != item.getTV().id) {
+ itemPosition = item.getTV().id
tvListViewModel.setItemPosition(itemPosition)
tvListViewModel.getTVViewModel(itemPosition)?.changed()
}
@@ -211,15 +209,18 @@ class MainFragment : BrowseSupportFragment() {
itemViewHolder: Presenter.ViewHolder?, item: Any?,
rowViewHolder: RowPresenter.ViewHolder, row: Row
) {
+// if (itemViewHolder !=null) {
+// (itemViewHolder.view as ImageCardView).setInfoAreaBackgroundColor(resources.getColor(R.color.focus))
+// }
if (item is TVViewModel) {
- tvListViewModel.setItemPositionCurrent(item.id.value!!)
+ tvListViewModel.setItemPositionCurrent(item.getTV().id)
(activity as MainActivity).mainActive()
}
}
}
fun check(tvViewModel: TVViewModel): Boolean {
- val title = tvViewModel.title.value
+ val title = tvViewModel.getTV().title
val videoUrl = tvViewModel.videoIndex.value?.let { tvViewModel.videoUrl.value?.get(it) }
if (videoUrl == null || videoUrl == "") {
Log.e(TAG, "$title videoUrl is empty")
diff --git a/app/src/main/java/com/lizongying/mytv/NetworkChangeReceiver.kt b/app/src/main/java/com/lizongying/mytv/NetworkChangeReceiver.kt
new file mode 100644
index 0000000..98ed850
--- /dev/null
+++ b/app/src/main/java/com/lizongying/mytv/NetworkChangeReceiver.kt
@@ -0,0 +1,16 @@
+package com.lizongying.mytv
+
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.net.ConnectivityManager
+
+class NetworkChangeReceiver : BroadcastReceiver() {
+ override fun onReceive(context: Context?, intent: Intent?) {
+ if (intent?.action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
+ val isConnected = context?.isNetworkConnected
+ if (isConnected == true) {
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/lizongying/mytv/PlayerFragment.kt b/app/src/main/java/com/lizongying/mytv/PlayerFragment.kt
index 81f7ccc..4c89712 100644
--- a/app/src/main/java/com/lizongying/mytv/PlayerFragment.kt
+++ b/app/src/main/java/com/lizongying/mytv/PlayerFragment.kt
@@ -82,6 +82,13 @@ class PlayerFragment : Fragment(), SurfaceHolder.Callback {
Log.e(TAG, "PlaybackException $error")
tvViewModel?.changed()
}
+
+ override fun onIsPlayingChanged(isPlaying: Boolean) {
+ super.onIsPlayingChanged(isPlaying)
+ if (isPlaying) {
+ (activity as MainActivity).isPlaying()
+ }
+ }
})
}
})
diff --git a/app/src/main/java/com/lizongying/mytv/Request.kt b/app/src/main/java/com/lizongying/mytv/Request.kt
index a27cdb5..903618a 100644
--- a/app/src/main/java/com/lizongying/mytv/Request.kt
+++ b/app/src/main/java/com/lizongying/mytv/Request.kt
@@ -24,6 +24,9 @@ import com.lizongying.mytv.api.YSPTokenService
import com.lizongying.mytv.models.TVViewModel
import com.lizongying.mytv.proto.Ysp.cn.yangshipin.oms.common.proto.pageModel
import com.lizongying.mytv.proto.Ysp.cn.yangshipin.omstv.common.proto.epgProgramModel
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
@@ -57,7 +60,7 @@ object Request {
private var listener: RequestListener? = null
private var initRetryTimes = 0
- private var initRetryMaxTimes = 1
+ private var initRetryMaxTimes = 0
fun onCreate() {
Log.i(TAG, "onCreate")
@@ -86,7 +89,7 @@ object Request {
private fun fetchAuth(tvModel: TVViewModel, cookie: String) {
cancelCall()
- val title = tvModel.title.value
+ val title = tvModel.getTV().title
val data = YSP.getAuthData(tvModel)
val request = AuthRequest(data)
@@ -166,17 +169,24 @@ object Request {
handler.removeCallbacks(btraceRunnable)
}
- val title = tvModel.title.value
+ val title = tvModel.getTV().title
tvModel.seq = 0
val data = YSP.switch(tvModel)
val request = LiveInfoRequest(data)
call = request.let {
- yspApiService.getLiveInfo(
- "guid=${YSP.getGuid()}; $cookie",
- YSP.token,
- it
- )
+ if (token == "") {
+ yspApiService.getLiveInfoV2(
+ "guid=${YSP.getGuid()}; $cookie",
+ it,
+ )
+ } else {
+ yspApiService.getLiveInfo(
+ "guid=${YSP.getGuid()}; $cookie",
+ YSP.token,
+ it
+ )
+ }
}
call?.enqueue(object : Callback {
@@ -413,7 +423,7 @@ object Request {
private fun fetchFAuth(tvModel: TVViewModel) {
cancelCall()
- val title = tvModel.title.value
+ val title = tvModel.getTV().title
var qa = "HD"
if (tokenFH != "") {
@@ -455,6 +465,9 @@ object Request {
}
if (tvModel.getTV().needToken) {
+ if (token == "") {
+ tvModel.needGetToken = true
+ }
if (needAuth) {
fetchAuth(tvModel)
} else {
@@ -462,7 +475,7 @@ object Request {
}
} else {
val cookie =
- "versionName=99.99.99; versionCode=999999; vplatform=109; platformVersion=Chrome; deviceModel=120; appid=1400421205"
+ "versionName=99.99.99; versionCode=999999; vplatform=109; platformVersion=Chrome; updateProtocol=1; deviceModel=120"
if (needAuth) {
fetchAuth(tvModel, cookie)
} else {
@@ -516,7 +529,7 @@ object Request {
Utils.setBetween(c * 1000L)
Log.i(TAG, "current time $c")
}
- listener?.onRequestFinished()
+ listener?.onRequestFinished(null)
} else {
Log.e(TAG, "token status error")
handler.postDelayed(
@@ -527,7 +540,7 @@ object Request {
initRetryTimes++
fetchInfoV2()
} else {
- listener?.onRequestFinished()
+ listener?.onRequestFinished("状态错误")
}
}
}
@@ -543,7 +556,7 @@ object Request {
initRetryTimes++
fetchInfoV2()
} else {
- listener?.onRequestFinished()
+ listener?.onRequestFinished("网络错误")
}
}
})
@@ -605,11 +618,11 @@ object Request {
}
fun fetchBtrace(tvModel: TVViewModel) {
- val title = tvModel.title.value
+ val title = tvModel.getTV().title
val guid = YSP.getGuid()
- val pid = tvModel.pid.value!!
- val sid = tvModel.sid.value!!
+ val pid = tvModel.getTV().pid
+ val sid = tvModel.getTV().sid
yspBtraceService.kvcollect(
c_timestamp = YSP.generateGuid(),
guid = guid,
@@ -675,8 +688,8 @@ object Request {
}
fun fetchYEPG(tvViewModel: TVViewModel) {
- val title = tvViewModel.title.value
- yspProtoService.getProgram(tvViewModel.programId.value!!, getDateFormat("yyyyMMdd"))
+ val title = tvViewModel.getTV().title
+ yspProtoService.getProgram(tvViewModel.getTV().programId, getDateFormat("yyyyMMdd"))
.enqueue(object : Callback {
override fun onResponse(
call: Call,
@@ -700,8 +713,8 @@ object Request {
}
fun fetchFEPG(tvViewModel: TVViewModel) {
- val title = tvViewModel.title.value
- fAuthService.getEPG(tvViewModel.pid.value!!, getDateFormat("yyyyMMdd"))
+ val title = tvViewModel.getTV().title
+ fAuthService.getEPG(tvViewModel.getTV().pid, getDateFormat("yyyyMMdd"))
.enqueue(object : Callback> {
override fun onResponse(
call: Call>,
@@ -738,7 +751,7 @@ object Request {
}
interface RequestListener {
- fun onRequestFinished()
+ fun onRequestFinished(message: String?)
}
fun setRequestListener(listener: RequestListener) {
diff --git a/app/src/main/java/com/lizongying/mytv/SettingFragment.kt b/app/src/main/java/com/lizongying/mytv/SettingFragment.kt
index 10fc5a6..cb6f9a5 100644
--- a/app/src/main/java/com/lizongying/mytv/SettingFragment.kt
+++ b/app/src/main/java/com/lizongying/mytv/SettingFragment.kt
@@ -5,12 +5,12 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.DialogFragment
-import com.lizongying.mytv.databinding.DialogBinding
+import com.lizongying.mytv.databinding.SettingBinding
class SettingFragment : DialogFragment() {
- private var _binding: DialogBinding? = null
+ private var _binding: SettingBinding? = null
private val binding get() = _binding!!
private lateinit var updateManager: UpdateManager
@@ -26,7 +26,7 @@ class SettingFragment : DialogFragment() {
savedInstanceState: Bundle?
): View {
val context = requireContext() // It‘s safe to get context here.
- _binding = DialogBinding.inflate(inflater, container, false)
+ _binding = SettingBinding.inflate(inflater, container, false)
binding.versionName.text = "当前版本: v${context.appVersionName}"
binding.version.text = "https://github.com/lizongying/my-tv"
@@ -76,11 +76,6 @@ class SettingFragment : DialogFragment() {
_binding = null
}
- override fun onDestroy() {
- super.onDestroy()
-// updateManager.destroy()
- }
-
companion object {
const val TAG = "SettingFragment"
}
diff --git a/app/src/main/java/com/lizongying/mytv/TVList.kt b/app/src/main/java/com/lizongying/mytv/TVList.kt
index 9a6e939..e0a3bf3 100644
--- a/app/src/main/java/com/lizongying/mytv/TVList.kt
+++ b/app/src/main/java/com/lizongying/mytv/TVList.kt
@@ -1,12 +1,5 @@
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 {
val list: Map> by lazy {
setup()
@@ -967,66 +960,7 @@ object TVList {
}
}
val array = arrayOf("央视", "地方")
-// list = list.filterKeys { it in array }
+ list = list.filterKeys { it in array }
return list
}
-
- /**
- * 初始化
- *
- * @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> = mutableMapOf()
- //是否从服务器更新
- var updateFromServer = false
- //获取频道列表
- val tvList: List = 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)
- }
- }
- }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/lizongying/mytv/api/ApiClient.kt b/app/src/main/java/com/lizongying/mytv/api/ApiClient.kt
index a8fbb60..182f17a 100644
--- a/app/src/main/java/com/lizongying/mytv/api/ApiClient.kt
+++ b/app/src/main/java/com/lizongying/mytv/api/ApiClient.kt
@@ -9,6 +9,8 @@ import okhttp3.TlsVersion
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.converter.protobuf.ProtoConverterFactory
+import java.net.InetSocketAddress
+import java.net.Proxy
import javax.net.ssl.SSLContext
import javax.net.ssl.TrustManager
import javax.net.ssl.X509TrustManager
diff --git a/app/src/main/java/com/lizongying/mytv/api/YSP.kt b/app/src/main/java/com/lizongying/mytv/api/YSP.kt
index 5a20ae6..469dd4d 100644
--- a/app/src/main/java/com/lizongying/mytv/api/YSP.kt
+++ b/app/src/main/java/com/lizongying/mytv/api/YSP.kt
@@ -1,6 +1,7 @@
package com.lizongying.mytv.api
import android.content.Context
+import android.util.Log
import com.lizongying.mytv.Encryptor
import com.lizongying.mytv.MainActivity
import com.lizongying.mytv.SP
@@ -63,8 +64,8 @@ object YSP {
}
fun switch(tvModel: TVViewModel): String {
- livepid = tvModel.pid.value!!
- cnlid = tvModel.sid.value!!
+ livepid = tvModel.getTV().pid
+ cnlid = tvModel.getTV().sid
defn = "fhd"
randStr = getRand()
@@ -82,7 +83,7 @@ object YSP {
}
fun getAuthData(tvModel: TVViewModel): String {
- livepid = tvModel.pid.value!!
+ livepid = tvModel.getTV().pid
randStr = getRand()
diff --git a/app/src/main/java/com/lizongying/mytv/api/YSPApiService.kt b/app/src/main/java/com/lizongying/mytv/api/YSPApiService.kt
index e9bbee2..41a85c9 100644
--- a/app/src/main/java/com/lizongying/mytv/api/YSPApiService.kt
+++ b/app/src/main/java/com/lizongying/mytv/api/YSPApiService.kt
@@ -21,6 +21,18 @@ interface YSPApiService {
@Body request: LiveInfoRequest,
): Call
+ @POST("v1/player/get_live_info")
+ @Headers(
+ "content-type: application/json;charset=UTF-8",
+ "referer: https://www.yangshipin.cn/",
+ "yspappid: 519748109",
+ "user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
+ )
+ fun getLiveInfoV2(
+ @Header("cookie") cookie: String,
+ @Body request: LiveInfoRequest,
+ ): Call
+
@POST("v1/player/auth")
@Headers(
"content-type: application/x-www-form-urlencoded;charset=UTF-8",
diff --git a/app/src/main/java/com/lizongying/mytv/models/TVViewModel.kt b/app/src/main/java/com/lizongying/mytv/models/TVViewModel.kt
index 1288cfb..c2efea6 100644
--- a/app/src/main/java/com/lizongying/mytv/models/TVViewModel.kt
+++ b/app/src/main/java/com/lizongying/mytv/models/TVViewModel.kt
@@ -1,15 +1,9 @@
package com.lizongying.mytv.models
-import android.net.Uri
import android.util.Log
-import androidx.annotation.OptIn
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
-import androidx.media3.common.MediaItem
-import androidx.media3.common.util.UnstableApi
-import androidx.media3.datasource.DefaultHttpDataSource
-import androidx.media3.exoplayer.hls.HlsMediaSource
import com.lizongying.mytv.TV
import com.lizongying.mytv.api.FEPG
import com.lizongying.mytv.proto.Ysp.cn.yangshipin.omstv.common.proto.programModel.Program
@@ -26,7 +20,7 @@ class TVViewModel(private var tv: TV) : ViewModel() {
var tokenYSPRetryTimes = 0
var tokenYSPRetryMaxTimes = 0
var tokenFHRetryTimes = 0
- var tokenFHRetryMaxTimes = 4
+ var tokenFHRetryMaxTimes = 8
var needGetToken = false
@@ -34,22 +28,10 @@ class TVViewModel(private var tv: TV) : ViewModel() {
val errInfo: LiveData
get() = _errInfo
- private val _programId = MutableLiveData()
- val programId: LiveData
- get() = _programId
-
private var _epg = MutableLiveData>()
val epg: LiveData>
get() = _epg
- private val _id = MutableLiveData()
- val id: LiveData
- get() = _id
-
- private val _title = MutableLiveData()
- val title: LiveData
- get() = _title
-
private val _videoUrl = MutableLiveData>()
val videoUrl: LiveData>
get() = _videoUrl
@@ -58,18 +40,6 @@ class TVViewModel(private var tv: TV) : ViewModel() {
val videoIndex: LiveData
get() = _videoIndex
- private val _logo = MutableLiveData()
- val logo: LiveData
- get() = _logo
-
- private val _pid = MutableLiveData()
- val pid: LiveData
- get() = _pid
-
- private val _sid = MutableLiveData()
- val sid: LiveData
- get() = _sid
-
private val _change = MutableLiveData()
val change: LiveData
get() = _change
@@ -116,14 +86,8 @@ class TVViewModel(private var tv: TV) : ViewModel() {
}
init {
- _id.value = tv.id
- _title.value = tv.title
_videoUrl.value = tv.videoUrl
_videoIndex.value = tv.videoUrl.lastIndex
- _logo.value = tv.logo
- _programId.value = tv.programId
- _pid.value = tv.pid
- _sid.value = tv.sid
}
fun getRowPosition(): Int {
@@ -146,10 +110,6 @@ class TVViewModel(private var tv: TV) : ViewModel() {
_errInfo.value = info
}
- fun update(t: TV) {
- tv = t
- }
-
fun getTV(): TV {
return tv
}
@@ -172,21 +132,6 @@ class TVViewModel(private var tv: TV) : ViewModel() {
_epg.value = p.map { EPG(it.title, formatFTime(it.event_time)) }.toMutableList()
}
- /**
- * (playerView?.player as ExoPlayer).setMediaSource(tvViewModel.buildSource())
- */
- @OptIn(UnstableApi::class)
- fun buildSource(): HlsMediaSource {
- val httpDataSource = DefaultHttpDataSource.Factory()
-// mHeaders?.let { httpDataSource.setDefaultRequestProperties(it) }
-
- return HlsMediaSource.Factory(httpDataSource).createMediaSource(
- MediaItem.fromUri(
- Uri.parse(getVideoUrlCurrent())
- )
- )
- }
-
fun getVideoUrlCurrent(): String {
return _videoUrl.value!![_videoIndex.value!!]
}
diff --git a/app/src/main/res/layout/dialog.xml b/app/src/main/res/layout/setting.xml
similarity index 100%
rename from app/src/main/res/layout/dialog.xml
rename to app/src/main/res/layout/setting.xml
diff --git a/app/src/main/res/raw/channels.json b/app/src/main/res/raw/channels.json
deleted file mode 100644
index 2d6443a..0000000
--- a/app/src/main/res/raw/channels.json
+++ /dev/null
@@ -1,892 +0,0 @@
-[
- {
- "id": 0,
- "channel": "央视",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/d57905b93540bd15f0c48230dbbbff7ee0d645ff539e38866e2d15c8b9f7dfcd.png?imageMogr2/format/webp",
- "pid": "600001859",
- "sid": "2000210103",
- "programId": "600001859",
- "needToken": false,
- "mustToken": false,
- "title": "CCTV1 综合",
- "videoUrl": [
- "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226231/index.m3u8"
- ]
- },
- {
- "id": 1,
- "channel": "央视",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/20115388de0207131af17eac86c33049b95d69eaff064e55653a1b941810a006.png?imageMogr2/format/webp",
- "pid": "600001800",
- "sid": "2000203603",
- "programId": "600001800",
- "needToken": true,
- "mustToken": false,
- "title": "CCTV2 财经",
- "videoUrl": [
- "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226195/index.m3u8"
- ]
- },
- {
- "id": 2,
- "channel": "央视",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/7b7a65c712450da3deb6ca66fbacf4f9aee00d3f20bd80eafb5ada01ec63eb3a.png?imageMogr2/format/webp",
- "pid": "600001801",
- "sid": "2000203803",
- "programId": "600001801",
- "needToken": true,
- "mustToken": true,
- "title": "CCTV3 综艺",
- "videoUrl": [
- "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226397/index.m3u8"
- ]
- },
- {
- "id": 3,
- "channel": "央视",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/f357e58fdbcc076a3d65e1f958c942b2e14f14342c60736ceed98b092d35356a.png?imageMogr2/format/webp",
- "pid": "600001814",
- "sid": "2000204803",
- "programId": "600001814",
- "needToken": false,
- "mustToken": false,
- "title": "CCTV4 中文国际",
- "videoUrl": [
- "http://39.134.24.161/dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226191/index.m3u8",
- "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226191/index.m3u8"
- ]
- },
- {
- "id": 4,
- "channel": "央视",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/0a6a7138952675983a3d854df7688557b286d59aa06166edae51506f9204d655.png?imageMogr2/format/webp",
- "pid": "600001818",
- "sid": "2000205103",
- "programId": "600001818",
- "needToken": true,
- "mustToken": false,
- "title": "CCTV5 体育",
- "videoUrl": [
- "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226395/index.m3u8"
- ]
- },
- {
- "id": 5,
- "channel": "央视",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/741515efda91f03f455df8a7da4ee11fa9329139c276435cf0a9e2af398d5bf2.png?imageMogr2/format/webp",
- "pid": "600001802",
- "sid": "2013693901",
- "programId": "600001802",
- "needToken": true,
- "mustToken": true,
- "title": "CCTV6 电影",
- "videoUrl": [
- "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226393/index.m3u8"
- ]
- },
- {
- "id": 6,
- "channel": "央视",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/b29af94e295ebdf646cefb68122c429b9cd921f498ca20d2d8070252536f9ff9.png?imageMogr2/format/webp",
- "pid": "600004092",
- "sid": "2000510003",
- "programId": "600004092",
- "needToken": true,
- "mustToken": false,
- "title": "CCTV7 国防军事",
- "videoUrl": [
- "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226192/index.m3u8"
- ]
- },
- {
- "id": 7,
- "channel": "央视",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/ad51de94426a0ba039e6dd6a8534ea98ecc813a6176bde87b4f18cc34d6d7590.png?imageMogr2/format/webp",
- "pid": "600001803",
- "sid": "2000203903",
- "programId": "600001803",
- "needToken": true,
- "mustToken": true,
- "title": "CCTV8 电视剧",
- "videoUrl": [
- "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226391/index.m3u8"
- ]
- },
- {
- "id": 8,
- "channel": "央视",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/2ed1b4deeca179d5db806bb941790f82eb92a1b7299c1c38fe027f95a5caee5e.png?imageMogr2/format/webp",
- "pid": "600004078",
- "sid": "2000499403",
- "programId": "600004078",
- "needToken": true,
- "mustToken": false,
- "title": "CCTV9 纪录",
- "videoUrl": [
- "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226197/index.m3u8"
- ]
- },
- {
- "id": 9,
- "channel": "央视",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/aa6157ec65188cd41826e5a2f088c3d6d153205f5f6428258d12c59999e221aa.png?imageMogr2/format/webp",
- "pid": "600001805",
- "sid": "2000203503",
- "programId": "600001805",
- "needToken": true,
- "mustToken": false,
- "title": "CCTV10 科教",
- "videoUrl": [
- "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226189/index.m3u8"
- ]
- },
- {
- "id": 10,
- "channel": "央视",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/ed12ed7c7a1034dae4350011fe039284c5d5a836506b28c9e32e3c75299625c0.png?imageMogr2/format/webp",
- "pid": "600001806",
- "sid": "2000204103",
- "programId": "600001806",
- "needToken": true,
- "mustToken": false,
- "title": "CCTV11 戏曲",
- "videoUrl": [
- "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226240/index.m3u8"
- ]
- },
- {
- "id": 11,
- "channel": "央视",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/484083cffaa40df7e659565e8cb4d1cc740158a185512114167aa21fa0c59240.png?imageMogr2/format/webp",
- "pid": "600001807",
- "sid": "2000202603",
- "programId": "600001807",
- "needToken": true,
- "mustToken": false,
- "title": "CCTV12 社会与法",
- "videoUrl": [
- "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226190/index.m3u8"
- ]
- },
- {
- "id": 12,
- "channel": "央视",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/266da7b43c03e2312186b4a999e0f060e8f15b10d2cc2c9aa32171819254cf1a.png?imageMogr2/format/webp",
- "pid": "600001811",
- "sid": "2000204603",
- "programId": "600001811",
- "needToken": false,
- "mustToken": false,
- "title": "CCTV13 新闻",
- "videoUrl": [
- "https://live-play.cctvnews.cctv.com/cctv/merge_cctv13.m3u8",
- "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226233/index.m3u8"
- ]
- },
- {
- "id": 13,
- "channel": "央视",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/af6b603896938dc346fbb16abfc63c12cba54b0ec9d18770a15d347d115f12d5.png?imageMogr2/format/webp",
- "pid": "600001809",
- "sid": "2000204403",
- "programId": "600001809",
- "needToken": true,
- "mustToken": false,
- "title": "CCTV14 少儿",
- "videoUrl": [
- "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226193/index.m3u8"
- ]
- },
- {
- "id": 14,
- "channel": "央视",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/2ceee92188ef684efe0d8b90839c4f3ad450d179dc64d59beff417059453af47.png?imageMogr2/format/webp",
- "pid": "600001815",
- "sid": "2000205003",
- "programId": "600001815",
- "needToken": true,
- "mustToken": false,
- "title": "CCTV15 音乐",
- "videoUrl": [
- "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225785/index.m3u8"
- ]
- },
- {
- "id": 15,
- "channel": "央视",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/53793fa7bacd3a93ff6dc5d2758418985e1f952a316c335d663b572d8bdcd74d.png?imageMogr2/format/webp",
- "pid": "600098637",
- "sid": "2012375003",
- "programId": "600098637",
- "needToken": true,
- "mustToken": false,
- "title": "CCTV16 奥林匹克",
- "videoUrl": [
- "http://39.134.24.162/dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226921/index.m3u8",
- "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226921/index.m3u8"
- ]
- },
- {
- "id": 16,
- "channel": "央视",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/ddef563072f8bad2bea5b9e52674cb7b4ed50efb20c26e61994dfbdf05c1e3c0.png?imageMogr2/format/webp",
- "pid": "600001810",
- "sid": "2000204203",
- "programId": "600001810",
- "needToken": true,
- "mustToken": false,
- "title": "CCTV17 农业农村",
- "videoUrl": [
- "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226198/index.m3u8"
- ]
- },
- {
- "id": 17,
- "channel": "央视",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/649ad76a90bfef55b05db9fe52e006487280f619089099d5dc971e387fc6eff0.png?imageMogr2/format/webp",
- "pid": "600001817",
- "sid": "2000204503",
- "programId": "600001817",
- "needToken": true,
- "mustToken": false,
- "title": "CCTV5+ 体育赛事",
- "videoUrl": [
- "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226221/index.m3u8"
- ]
- },
- {
- "id": 18,
- "channel": "央视",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/3e9d06fd7244d950df5838750f1c6ac3456e172b51caca2c16d2282125b111e8.png?imageMogr2/format/webp",
- "pid": "600002264",
- "sid": "2000266303",
- "programId": "600002264",
- "needToken": true,
- "mustToken": false,
- "title": "CCTV4K 超高清",
- "videoUrl": [
- ""
- ]
- },
- {
- "id": 19,
- "channel": "央视",
- "logo": "",
- "pid": "600156816",
- "sid": "2020603421",
- "programId": "",
- "needToken": false,
- "mustToken": false,
- "title": "CCTV8K 超高清",
- "videoUrl": [
- ""
- ]
- },
- {
- "id": 20,
- "channel": "央视",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/4d549e53e6d0f632d5a633d1945280797b153e588f919221a07faa869812cc89.png?imageMogr2/format/webp",
- "pid": "600099658",
- "sid": "2012513603",
- "programId": "600099658",
- "needToken": true,
- "mustToken": true,
- "title": "风云剧场",
- "videoUrl": [
- "http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226950/index.m3u8"
- ]
- },
- {
- "id": 21,
- "channel": "央视",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/a556bd7d93ce65e18f243a8892b5604f4faa994a4897315914216a710a706208.png?imageMogr2/format/webp",
- "pid": "600099655",
- "sid": "2012514403",
- "programId": "600099655",
- "needToken": true,
- "mustToken": true,
- "title": "第一剧场",
- "videoUrl": [
- "http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226959/index.m3u8"
- ]
- },
- {
- "id": 22,
- "channel": "央视",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/5661bd04fecdb6e899f801147a22ab5d3a475bf2b62e30aec2c0023190ebc9b1.png?imageMogr2/format/webp",
- "pid": "600099620",
- "sid": "2012511203",
- "programId": "600099620",
- "needToken": true,
- "mustToken": true,
- "title": "怀旧剧场",
- "videoUrl": [
- "http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226972/index.m3u8"
- ]
- },
- {
- "id": 23,
- "channel": "央视",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/bb3c6c9e145d698137f5bb64a582021a01b51344b929003630eb769ea65832a9.png?imageMogr2/format/webp",
- "pid": "600099637",
- "sid": "2012513303",
- "programId": "600099637",
- "needToken": true,
- "mustToken": true,
- "title": "世界地理",
- "videoUrl": [
- ""
- ]
- },
- {
- "id": 24,
- "channel": "央视",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/bbf1d024c5228b8dd128b0e3cb1717d173fab4ee84c3a4c8a57b1a215362ca3b.png?imageMogr2/format/webp",
- "pid": "600099660",
- "sid": "2012514103",
- "programId": "600099660",
- "needToken": true,
- "mustToken": true,
- "title": "风云音乐",
- "videoUrl": [
- "http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226953/index.m3u8"
- ]
- },
- {
- "id": 25,
- "channel": "央视",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/4c6b6a6d3839889f34d33db3c2f80233b26b74d3489b393487635f8704e70796.png?imageMogr2/format/webp",
- "pid": "600099649",
- "sid": "2012513403",
- "programId": "600099649",
- "needToken": true,
- "mustToken": true,
- "title": "兵器科技",
- "videoUrl": [
- "http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226975/index.m3u8"
- ]
- },
- {
- "id": 26,
- "channel": "央视",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/cd1e2bb52b06a991de168733e5ff0f1d85adc8042d40c8f393f723543e5dd08a.png?imageMogr2/format/webp",
- "pid": "600099636",
- "sid": "2012514203",
- "programId": "600099636",
- "needToken": true,
- "mustToken": true,
- "title": "风云足球",
- "videoUrl": [
- "http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226984/index.m3u8"
- ]
- },
- {
- "id": 27,
- "channel": "央视",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/cdd1b31ede7a5ad049ed53d9a072422f829e72dd062ed2c19e077fdd01699071.png?imageMogr2/format/webp",
- "pid": "600099659",
- "sid": "2012512503",
- "programId": "600099659",
- "needToken": true,
- "mustToken": true,
- "title": "高尔夫网球",
- "videoUrl": [
- "http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226978/index.m3u8"
- ]
- },
- {
- "id": 28,
- "channel": "央视",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/fa28955ce8b2539d728bf4c6a13a46ff57ad76eae46627f7bcfb1ed8a613d3fc.png?imageMogr2/format/webp",
- "pid": "600099650",
- "sid": "2012513903",
- "programId": "600099650",
- "needToken": true,
- "mustToken": true,
- "title": "女性时尚",
- "videoUrl": [
- "http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226969/index.m3u8"
- ]
- },
- {
- "id": 29,
- "channel": "央视",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/14ac5ce40482cacd3d4b37435222bfe86af2b452a2f04ecbfc1d13d76edd7c57.png?imageMogr2/format/webp",
- "pid": "600099653",
- "sid": "2012513803",
- "programId": "600099653",
- "needToken": true,
- "mustToken": true,
- "title": "央视文化精品",
- "videoUrl": [
- "http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226981/index.m3u8"
- ]
- },
- {
- "id": 30,
- "channel": "央视",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/10e14a92478011aa6c3c8562e62127f3b1908e29fcd78e4b2b24b9e6d3ec2fbc.png?imageMogr2/format/webp",
- "pid": "600099652",
- "sid": "2012513703",
- "programId": "600099652",
- "needToken": true,
- "mustToken": true,
- "title": "央视台球",
- "videoUrl": [
- "http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226956/index.m3u8"
- ]
- },
- {
- "id": 31,
- "channel": "央视",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/244d72c0eb1615ed7d51c2f5db5a67f306aa3f58c05bc2d34de3aa7e956dc8c9.png?imageMogr2/format/webp",
- "pid": "600099656",
- "sid": "2012514003",
- "programId": "600099656",
- "needToken": true,
- "mustToken": true,
- "title": "电视指南",
- "videoUrl": [
- "http://dbiptv.sn.chinamobile.com/PLTV/88888893/224/3221226987/index.m3u8"
- ]
- },
- {
- "id": 32,
- "channel": "央视",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/54a6863656fdfd8f803be193ddf22441c5000a108833889816fd2d8911715ce8.png?imageMogr2/format/webp",
- "pid": "600099651",
- "sid": "2012513503",
- "programId": "600099651",
- "needToken": true,
- "mustToken": true,
- "title": "卫生健康",
- "videoUrl": [
- ""
- ]
- },
- {
- "id": 33,
- "channel": "地方",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/9bd372ca292a82ce3aa08772b07efc4af1f85c21d1f268ea33440c49e9a0a488.png?imageMogr2/format/webp",
- "pid": "600002483",
- "sid": "2000292403",
- "programId": "600002483",
- "needToken": true,
- "mustToken": false,
- "title": "东方卫视",
- "videoUrl": [
- "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226217/index.m3u8"
- ]
- },
- {
- "id": 34,
- "channel": "地方",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/4120e89d3079d08aa17d382f69a2308ec70839b278367763c34a34666c75cb88.png?imageMogr2/format/webp",
- "pid": "600002475",
- "sid": "2000296203",
- "programId": "600002475",
- "needToken": true,
- "mustToken": false,
- "title": "湖南卫视",
- "videoUrl": [
- "http://ottrrs.hl.chinamobile.com/PLTV/88888888/224/3221226307/index.m3u8",
- "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226211/index.m3u8"
- ]
- },
- {
- "id": 35,
- "channel": "地方",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/7a6be5a2bb1dc53a945c016ff1f525dc4a84c51db371c15c89aa55404b0ba784.png?imageMogr2/format/webp",
- "pid": "600002508",
- "sid": "2000294503",
- "programId": "600002508",
- "needToken": true,
- "mustToken": false,
- "title": "湖北卫视",
- "videoUrl": [
- "http://ottrrs.hl.chinamobile.com/PLTV/88888888/224/3221226477/index.m3u8",
- "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226194/index.m3u8"
- ]
- },
- {
- "id": 36,
- "channel": "地方",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/ac4ed6058a87c101ae7147ebc38905d0cae047fb73fd277ee5049b84f52bda36.png?imageMogr2/format/webp",
- "pid": "600002505",
- "sid": "2000281303",
- "programId": "600002505",
- "needToken": true,
- "mustToken": false,
- "title": "辽宁卫视",
- "videoUrl": [
- "http://ottrrs.hl.chinamobile.com/PLTV/88888888/224/3221226546/index.m3u8",
- "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226201/index.m3u8"
- ]
- },
- {
- "id": 37,
- "channel": "地方",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/380ad685c0c1d5b2c902246b8d2df6d3f9b45e2837abcfe493075bbded597a31.png?imageMogr2/format/webp",
- "pid": "600002521",
- "sid": "2000295603",
- "programId": "600002521",
- "needToken": true,
- "mustToken": false,
- "title": "江苏卫视",
- "videoUrl": [
- "http://39.134.24.166/dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226200/index.m3u8",
- "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226200/index.m3u8"
- ]
- },
- {
- "id": 38,
- "channel": "地方",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/3c760d0d00463855890e8a1864ea4a6b6dd66b90c29b4ac714a4b17c16519871.png?imageMogr2/format/webp",
- "pid": "600002503",
- "sid": "2000294103",
- "programId": "600002503",
- "needToken": true,
- "mustToken": false,
- "title": "江西卫视",
- "videoUrl": [
- "http://ottrrs.hl.chinamobile.com/PLTV/88888888/224/3221226344/index.m3u8",
- "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225764/index.m3u8"
- ]
- },
- {
- "id": 39,
- "channel": "地方",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/22d403f07a7cf5410b3ad3ddb65a11aa229a32475fac213f5344c9f0ec330ca1.png?imageMogr2/format/webp",
- "pid": "600002513",
- "sid": "2000294803",
- "programId": "600002513",
- "needToken": true,
- "mustToken": false,
- "title": "山东卫视",
- "videoUrl": [
- "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226209/index.m3u8"
- ]
- },
- {
- "id": 40,
- "channel": "地方",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/28886880a4dc0f06fb7e0a528a1def0591d61a65870e29176ede0cc92033bbfd.png?imageMogr2/format/webp",
- "pid": "600002485",
- "sid": "2000292703",
- "programId": "600002485",
- "needToken": true,
- "mustToken": false,
- "title": "广东卫视",
- "videoUrl": [
- "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226216/index.m3u8"
- ]
- },
- {
- "id": 41,
- "channel": "地方",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/54b7e97cb816bb223fe05f3fc44da2c7820eb66e8550c19d23100f2c414ecc38.png?imageMogr2/format/webp",
- "pid": "600002509",
- "sid": "2000294203",
- "programId": "600002509",
- "needToken": true,
- "mustToken": false,
- "title": "广西卫视",
- "videoUrl": [
- "http://live.gxrb.com.cn/tv/gxtvlive03/index.m3u8",
- "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225770/index.m3u8"
- ]
- },
- {
- "id": 42,
- "channel": "地方",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/657651f411de2673d1770d9a78b44c1265704f7468cc41d4be7f51d630768494.png?imageMogr2/format/webp",
- "pid": "600002531",
- "sid": "2000297803",
- "programId": "600002531",
- "needToken": true,
- "mustToken": false,
- "title": "重庆卫视",
- "videoUrl": [
- "http://ottrrs.hl.chinamobile.com/PLTV/88888888/224/3221226409/index.m3u8",
- "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226202/index.m3u8"
- ]
- },
- {
- "id": 43,
- "channel": "地方",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/74925962148a6d31c85808b6cd4e444c2a54bab393d2c5fc85e960b50e22fa86.png?imageMogr2/format/webp",
- "pid": "600002525",
- "sid": "2000296103",
- "programId": "600002525",
- "needToken": true,
- "mustToken": false,
- "title": "河南卫视",
- "videoUrl": [
- "http://ottrrs.hl.chinamobile.com/PLTV/88888888/224/3221226480/index.m3u8",
- "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225767/index.m3u8"
- ]
- },
- {
- "id": 44,
- "channel": "地方",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/d545becdc81c60197b08c7f47380705e4665ed3fe55efc8b855e486f6e655378.png?imageMogr2/format/webp",
- "pid": "600002493",
- "sid": "2000293403",
- "programId": "600002493",
- "needToken": true,
- "mustToken": false,
- "title": "河北卫视",
- "videoUrl": [
- "http://ottrrs.hl.chinamobile.com/PLTV/88888888/224/3221226406/index.m3u8",
- "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225750/index.m3u8"
- ]
- },
- {
- "id": 45,
- "channel": "地方",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/4eb45f4781d33d872af027dc01c941559aab55667dd99cc5c22bef7037807b13.png?imageMogr2/format/webp",
- "pid": "600002490",
- "sid": "2000293303",
- "programId": "600002490",
- "needToken": true,
- "mustToken": false,
- "title": "贵州卫视",
- "videoUrl": [
- "http://ottrrs.hl.chinamobile.com/PLTV/88888888/224/3221226474/index.m3u8",
- "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225793/index.m3u8"
- ]
- },
- {
- "id": 46,
- "channel": "地方",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/f4f23633c578beea49a3841d88d3490100f029ee349059fa532869db889872c5.png?imageMogr2/format/webp",
- "pid": "600002309",
- "sid": "2000272103",
- "programId": "600002309",
- "needToken": true,
- "mustToken": false,
- "title": "北京卫视",
- "videoUrl": [
- "http://ottrrs.hl.chinamobile.com/PLTV/88888888/224/3221225728/index.m3u8",
- "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226222/index.m3u8"
- ]
- },
- {
- "id": 47,
- "channel": "地方",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/d8273ae9be698ce2db21f5b886ecac95a73429593f93713c60ed8c12c38bf0d3.png?imageMogr2/format/webp",
- "pid": "600002498",
- "sid": "2000293903",
- "programId": "600002498",
- "needToken": true,
- "mustToken": false,
- "title": "黑龙江卫视",
- "videoUrl": [
- "http://ottrrs.hl.chinamobile.com/PLTV/88888888/224/3221226327/index.m3u8",
- "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226215/index.m3u8"
- ]
- },
- {
- "id": 48,
- "channel": "地方",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/a66c836bd98ba3e41a2e9a570d4b9c50dedc6839e9de333e2e78212ad505f37e.png?imageMogr2/format/webp",
- "pid": "600002520",
- "sid": "2000295503",
- "programId": "600002520",
- "needToken": true,
- "mustToken": false,
- "title": "浙江卫视",
- "videoUrl": [
- "http://hw-m-l.cztv.com/channels/lantian/channel01/1080p.m3u8",
- "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226199/index.m3u8"
- ]
- },
- {
- "id": 49,
- "channel": "地方",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/f35fa04b51b1ee4984b03578b65403570868ebca03c6c01e11b097f999a58d9b.png?imageMogr2/format/webp",
- "pid": "600002532",
- "sid": "2000298003",
- "programId": "600002532",
- "needToken": true,
- "mustToken": false,
- "title": "安徽卫视",
- "videoUrl": [
- "http://ottrrs.hl.chinamobile.com/PLTV/88888888/224/3221226391/index.m3u8",
- "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226203/index.m3u8"
- ]
- },
- {
- "id": 50,
- "channel": "地方",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/d59fec04c902e3581c617136d02d4b9b8c4cbe64272781ddd3525e80c823edb7.png?imageMogr2/format/webp",
- "pid": "600002481",
- "sid": "2000292203",
- "programId": "600002481",
- "needToken": true,
- "mustToken": false,
- "title": "深圳卫视",
- "videoUrl": [
- "http://39.134.24.166/dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226205/index.m3u8",
- "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226205/index.m3u8"
- ]
- },
- {
- "id": 51,
- "channel": "地方",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/3276a414ae0eaa0f116f2045cd913367967d0c7c1e978e8621ac3879436c6ed7.png?imageMogr2/format/webp",
- "pid": "600002516",
- "sid": "2000295003",
- "programId": "600002516",
- "needToken": true,
- "mustToken": false,
- "title": "四川卫视",
- "videoUrl": [
- "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225768/index.m3u8",
- "http://39.134.24.166/dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225768/index.m3u8"
- ]
- },
- {
- "id": 52,
- "channel": "地方",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/3208fe6564a293c21b711333fb3edb05bb5b406cff840573c9a8d839680a1579.png?imageMogr2/format/webp",
- "pid": "600002484",
- "sid": "2000292503",
- "programId": "600002484",
- "needToken": true,
- "mustToken": false,
- "title": "东南卫视",
- "videoUrl": [
- "http://ottrrs.hl.chinamobile.com/PLTV/88888888/224/3221226341/index.m3u8",
- "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225766/index.m3u8"
- ]
- },
- {
- "id": 53,
- "channel": "地方",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/6e060391fde0469801fc3d84dbf204b4f8d650d251f17d7595a6964c0bb99e81.png?imageMogr2/format/webp",
- "pid": "600002506",
- "sid": "2000291503",
- "programId": "600002506",
- "needToken": true,
- "mustToken": false,
- "title": "海南卫视",
- "videoUrl": [
- "http://ottrrs.hl.chinamobile.com/PLTV/88888888/224/3221226465/index.m3u8",
- "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225769/index.m3u8"
- ]
- },
- {
- "id": 54,
- "channel": "地方",
- "logo": "",
- "pid": "600152137",
- "sid": "2019927003",
- "programId": "",
- "needToken": true,
- "mustToken": false,
- "title": "天津卫视",
- "videoUrl": [
- ""
- ]
- },
- {
- "id": 55,
- "channel": "地方",
- "logo": "",
- "pid": "600152138",
- "sid": "2019927403",
- "programId": "",
- "needToken": true,
- "mustToken": false,
- "title": "新疆卫视",
- "videoUrl": [
- ""
- ]
- },
- {
- "id": 56,
- "channel": "国际",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/a72dff758ca1c17cd0ecc8cedc11b893d208f409d5e6302faa0e9d298848abc3.png?imageMogr2/format/webp",
- "pid": "600014550",
- "sid": "2001656803",
- "programId": "600014550",
- "needToken": false,
- "mustToken": false,
- "title": "CGTN",
- "videoUrl": [
- "http://live.cgtn.com/1000/prog_index.m3u8"
- ]
- },
- {
- "id": 57,
- "channel": "国际",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/a8d0046a47433d952bf6ed17062deb8bd2184ba9aec0f7781df6bf9487a3ffcf.png?imageMogr2/format/webp",
- "pid": "600084704",
- "sid": "2010153503",
- "programId": "600084704",
- "needToken": false,
- "mustToken": false,
- "title": "CGTN 法语频道",
- "videoUrl": [
- "https://livefr.cgtn.com/1000f/prog_index.m3u8"
- ]
- },
- {
- "id": 58,
- "channel": "国际",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/bf0a820893cbaf20dd0333e27042e1ef9c8806e5b602b6a8c95af399db0bc77a.png?imageMogr2/format/webp",
- "pid": "600084758",
- "sid": "2010152603",
- "programId": "600084758",
- "needToken": false,
- "mustToken": false,
- "title": "CGTN 俄语频道",
- "videoUrl": [
- "http://liveru.cgtn.com/1000r/prog_index.m3u8"
- ]
- },
- {
- "id": 59,
- "channel": "国际",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202306/2e44e2aa3e7a1cedf07fd0ae59fe69e86a60a2632660a006e3e9e7397b2d107e.png?imageMogr2/format/webp",
- "pid": "600084782",
- "sid": "2010155203",
- "programId": "600084782",
- "needToken": false,
- "mustToken": false,
- "title": "CGTN 阿拉伯语频道",
- "videoUrl": [
- "http://livear.cgtn.com/1000a/prog_index.m3u8"
- ]
- },
- {
- "id": 60,
- "channel": "国际",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202309/7c337e3dbe64402ec7e4678a619a4a6d95144e42f35161181ff78e143b7cf67a.png?imageMogr2/format/webp",
- "pid": "600084744",
- "sid": "2010152503",
- "programId": "600084744",
- "needToken": false,
- "mustToken": false,
- "title": "CGTN 西班牙语频道",
- "videoUrl": [
- "http://livees.cgtn.com/500e/prog_index.m3u8",
- "http://livees.cgtn.com/1000e/prog_index.m3u8"
- ]
- },
- {
- "id": 61,
- "channel": "国际",
- "logo": "https://resources.yangshipin.cn/assets/oms/image/202309/74d3ac436a7e374879578de1d87a941fbf566d39d5632b027c5097891ed32bd5.png?imageMogr2/format/webp",
- "pid": "600084781",
- "sid": "2010155403",
- "programId": "600084781",
- "needToken": false,
- "mustToken": false,
- "title": "CGTN 纪录频道",
- "videoUrl": [
- "https://livedoc.cgtn.com/500d/prog_index.m3u8"
- ]
- }
-]
\ No newline at end of file
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index 78385ca..569cb10 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -1,5 +1,7 @@
+ #0096a6
#30000000
#000
#FFF
+ #223239
\ No newline at end of file
diff --git a/app/src/main/res/values/ic_launcher_background.xml b/app/src/main/res/values/ic_launcher_background.xml
deleted file mode 100644
index c6c36f6..0000000
--- a/app/src/main/res/values/ic_launcher_background.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
- #223239
-
\ No newline at end of file
diff --git a/app/src/main/res/values/server.xml b/app/src/main/res/values/server.xml
deleted file mode 100644
index af4facd..0000000
--- a/app/src/main/res/values/server.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
- 1
- https://fastly.jsdelivr.net/gh/LeGend-wLw/my-tv-json-utils@main/version.txt
- https://fastly.jsdelivr.net/gh/LeGend-wLw/my-tv-json-utils@main/channels.json
-
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 36adfb6..c5da028 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -4,4 +4,5 @@
数字选台
检查更新
开机自启
+ 好的
\ No newline at end of file