phoenix EPG

pull/718/head
Li ZongYing 2 years ago
parent 0c2beb936a
commit 7bed18ee6d
  1. 10
      app/src/main/java/com/lizongying/mytv/CardPresenter.kt
  2. 10
      app/src/main/java/com/lizongying/mytv/InfoFragment.kt
  3. 11
      app/src/main/java/com/lizongying/mytv/MainActivity.kt
  4. 43
      app/src/main/java/com/lizongying/mytv/MainFragment.kt
  5. 53
      app/src/main/java/com/lizongying/mytv/Request.kt
  6. 2038
      app/src/main/java/com/lizongying/mytv/TVList.kt
  7. 8
      app/src/main/java/com/lizongying/mytv/api/FAuthService.kt
  8. 7
      app/src/main/java/com/lizongying/mytv/api/FEPG.kt
  9. 7
      app/src/main/java/com/lizongying/mytv/models/EPG.kt
  10. 50
      app/src/main/java/com/lizongying/mytv/models/TVViewModel.kt
  11. BIN
      app/src/main/res/drawable/chongqing.png
  12. 2
      app/src/main/res/raw/channels.json

@ -39,11 +39,11 @@ class CardPresenter(
cardView.setBackgroundColor(Color.WHITE) cardView.setBackgroundColor(Color.WHITE)
cardView.setMainImageScaleType(ImageView.ScaleType.CENTER_INSIDE) cardView.setMainImageScaleType(ImageView.ScaleType.CENTER_INSIDE)
tvViewModel.program.observe(owner) { _ -> val epg = tvViewModel.epg.value?.filter { it.beginTime < Utils.getDateTimestamp() }
val program = tvViewModel.getProgramOne() if (!epg.isNullOrEmpty()) {
if (program != null) { cardView.contentText = epg.last().title
cardView.contentText = program.name } else {
} cardView.contentText = ""
} }
} }

@ -2,6 +2,7 @@ package com.lizongying.mytv
import android.os.Bundle import android.os.Bundle
import android.os.Handler import android.os.Handler
import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
@ -34,9 +35,12 @@ class InfoFragment : Fragment() {
.load(tvViewModel.logo.value) .load(tvViewModel.logo.value)
.into(binding.infoLogo) .into(binding.infoLogo)
val program = tvViewModel.getProgramOne() Log.i(TAG, "${tvViewModel.title.value} ${tvViewModel.epg.value}")
if (program != null) { val epg = tvViewModel.epg.value?.filter { it.beginTime < Utils.getDateTimestamp() }
binding.infoDesc.text = program.name if (!epg.isNullOrEmpty()) {
binding.infoDesc.text = epg.last().title
} else {
binding.infoDesc.text = ""
} }
handler.removeCallbacks(removeRunnable) handler.removeCallbacks(removeRunnable)

@ -36,16 +36,6 @@ class MainActivity : FragmentActivity(), Request.RequestListener {
private val delayHideMain: Long = 10000 private val delayHideMain: Long = 10000
private val delayHideSetting: 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?) { override fun onCreate(savedInstanceState: Bundle?) {
Log.i(TAG, "onCreate") Log.i(TAG, "onCreate")
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -459,5 +449,4 @@ class MainActivity : FragmentActivity(), Request.RequestListener {
private companion object { private companion object {
const val TAG = "MainActivity" const val TAG = "MainActivity"
} }
} }

@ -34,9 +34,6 @@ class MainFragment : BrowseSupportFragment() {
private var lastVideoUrl = "" private var lastVideoUrl = ""
private val handler = Handler(Looper.getMainLooper())
private lateinit var mUpdateProgramRunnable: UpdateProgramRunnable
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
Log.i(TAG, "onCreate") Log.i(TAG, "onCreate")
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -57,9 +54,6 @@ class MainFragment : BrowseSupportFragment() {
setupEventListeners() setupEventListeners()
mUpdateProgramRunnable = UpdateProgramRunnable()
handler.post(mUpdateProgramRunnable)
tvListViewModel.tvListViewModel.value?.forEach { tvViewModel -> tvListViewModel.tvListViewModel.value?.forEach { tvViewModel ->
tvViewModel.errInfo.observe(viewLifecycleOwner) { _ -> tvViewModel.errInfo.observe(viewLifecycleOwner) { _ ->
if (tvViewModel.errInfo.value != null if (tvViewModel.errInfo.value != null
@ -141,6 +135,8 @@ class MainFragment : BrowseSupportFragment() {
tvViewModel.setItemPosition(idx2) tvViewModel.setItemPosition(idx2)
tvListViewModel.addTVViewModel(tvViewModel) tvListViewModel.addTVViewModel(tvViewModel)
listRowAdapter.add(tvViewModel) listRowAdapter.add(tvViewModel)
updateEPG(tvViewModel)
} }
tvListViewModel.maxNum.add(v.size) tvListViewModel.maxNum.add(v.size)
val header = HeaderItem(idx, k) val header = HeaderItem(idx, k)
@ -277,30 +273,11 @@ class MainFragment : BrowseSupportFragment() {
} }
} }
fun updateProgram(tvViewModel: TVViewModel) { private fun updateEPG(tvViewModel: TVViewModel) {
val timestamp = getDateTimestamp() if (tvViewModel.getTV().channel == "港澳台") {
if (timestamp - tvViewModel.programUpdateTime > 60) { Request.fetchFEPG(tvViewModel)
if (tvViewModel.program.value!!.isEmpty()) { } else {
tvViewModel.programUpdateTime = timestamp Request.fetchYEPG(tvViewModel)
Request.fetchProgram(tvViewModel)
} else {
if (tvViewModel.program.value!!.last().et - timestamp < 600) {
tvViewModel.programUpdateTime = timestamp
Request.fetchProgram(tvViewModel)
}
}
}
}
inner class UpdateProgramRunnable : Runnable {
override fun run() {
tvListViewModel.tvListViewModel.value?.filter { it.programId.value != null && it.programId.value != "" }
?.forEach { tvViewModel ->
updateProgram(
tvViewModel
)
}
handler.postDelayed(this, 60000)
} }
} }
@ -313,18 +290,16 @@ class MainFragment : BrowseSupportFragment() {
Log.i(TAG, "onStop") Log.i(TAG, "onStop")
super.onStop() super.onStop()
SP.itemPosition = itemPosition SP.itemPosition = itemPosition
Log.i(TAG, "position saved") Log.i(TAG, "$POSITION $itemPosition saved")
} }
override fun onDestroy() { override fun onDestroy() {
Log.i(TAG, "onDestroy") Log.i(TAG, "onDestroy")
super.onDestroy() super.onDestroy()
if (::mUpdateProgramRunnable.isInitialized) {
handler.removeCallbacks(mUpdateProgramRunnable)
}
} }
companion object { companion object {
private const val TAG = "MainFragment" private const val TAG = "MainFragment"
private const val POSITION = "position"
} }
} }

@ -10,6 +10,7 @@ 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.FAuth
import com.lizongying.mytv.api.FAuthService import com.lizongying.mytv.api.FAuthService
import com.lizongying.mytv.api.FEPG
import com.lizongying.mytv.api.Info import com.lizongying.mytv.api.Info
import com.lizongying.mytv.api.InfoV2 import com.lizongying.mytv.api.InfoV2
import com.lizongying.mytv.api.LiveInfo import com.lizongying.mytv.api.LiveInfo
@ -400,7 +401,7 @@ object Request {
tvModel.allReady() tvModel.allReady()
tvModel.tokenRetryTimes = 0 tvModel.tokenRetryTimes = 0
} else { } else {
Log.e(TAG, "auth status error") Log.e(TAG, "auth status error ${response.code()}")
if (tvModel.tokenRetryTimes < tvModel.tokenRetryMaxTimes) { if (tvModel.tokenRetryTimes < tvModel.tokenRetryMaxTimes) {
tvModel.tokenRetryTimes++ tvModel.tokenRetryTimes++
fetchFAuth(tvModel) fetchFAuth(tvModel)
@ -419,7 +420,6 @@ object Request {
} }
fun fetchData(tvModel: TVViewModel) { fun fetchData(tvModel: TVViewModel) {
Log.d(TAG, "fetchData")
if (tvModel.getTV().channel == "港澳台") { if (tvModel.getTV().channel == "港澳台") {
fetchFAuth(tvModel) fetchFAuth(tvModel)
return return
@ -463,20 +463,20 @@ object Request {
if (e != null) { if (e != null) {
handler.postDelayed( handler.postDelayed(
tokenRunnable, tokenRunnable,
max(600000, (e - 1500) * 1000).toLong() max(30 * 60 * 1000, (e - 1500) * 1000).toLong()
) )
} else { } else {
Log.e(TAG, "e empty") Log.e(TAG, "e empty")
handler.postDelayed( handler.postDelayed(
tokenRunnable, tokenRunnable,
600000 30 * 60 * 1000
) )
} }
} else { } else {
Log.e(TAG, "token empty") Log.e(TAG, "token empty")
handler.postDelayed( handler.postDelayed(
tokenRunnable, tokenRunnable,
600000 30 * 60 * 1000
) )
} }
if (!f.isNullOrEmpty()) { if (!f.isNullOrEmpty()) {
@ -491,7 +491,7 @@ object Request {
Log.e(TAG, "token status error") Log.e(TAG, "token status error")
handler.postDelayed( handler.postDelayed(
tokenRunnable, tokenRunnable,
600000 30 * 60 * 1000
) )
} }
listener?.onRequestFinished() listener?.onRequestFinished()
@ -501,7 +501,7 @@ object Request {
Log.e(TAG, "token request error $t") Log.e(TAG, "token request error $t")
handler.postDelayed( handler.postDelayed(
tokenRunnable, tokenRunnable,
600000 30 * 60 * 1000
) )
listener?.onRequestFinished() listener?.onRequestFinished()
} }
@ -521,27 +521,27 @@ object Request {
if (e != null) { if (e != null) {
handler.postDelayed( handler.postDelayed(
tokenRunnable, tokenRunnable,
max(600000, (e - 1500) * 1000).toLong() max(30 * 60 * 1000, (e - 1500) * 1000).toLong()
) )
} else { } else {
Log.e(TAG, "e empty") Log.e(TAG, "e empty")
handler.postDelayed( handler.postDelayed(
tokenRunnable, tokenRunnable,
600000 30 * 60 * 1000
) )
} }
} else { } else {
Log.e(TAG, "token empty") Log.e(TAG, "token empty")
handler.postDelayed( handler.postDelayed(
tokenRunnable, tokenRunnable,
600000 30 * 60 * 1000
) )
} }
} else { } else {
Log.e(TAG, "token status error") Log.e(TAG, "token status error")
handler.postDelayed( handler.postDelayed(
tokenRunnable, tokenRunnable,
600000 30 * 60 * 1000
) )
} }
} }
@ -550,7 +550,7 @@ object Request {
Log.e(TAG, "token request error $t") Log.e(TAG, "token request error $t")
handler.postDelayed( handler.postDelayed(
tokenRunnable, tokenRunnable,
600000 30 * 60 * 1000
) )
} }
}) })
@ -632,7 +632,7 @@ object Request {
}) })
} }
fun fetchProgram(tvViewModel: TVViewModel) { fun fetchYEPG(tvViewModel: TVViewModel) {
val title = tvViewModel.title.value val title = tvViewModel.title.value
yspProtoService.getProgram(tvViewModel.programId.value!!, getDateFormat("yyyyMMdd")) yspProtoService.getProgram(tvViewModel.programId.value!!, getDateFormat("yyyyMMdd"))
.enqueue(object : Callback<epgProgramModel.Response> { .enqueue(object : Callback<epgProgramModel.Response> {
@ -643,7 +643,7 @@ object Request {
if (response.isSuccessful) { if (response.isSuccessful) {
val program = response.body() val program = response.body()
if (program != null) { if (program != null) {
tvViewModel.addProgram(program.dataListList) tvViewModel.addYEPG(program.dataListList)
Log.d(TAG, "$title program ${program.dataListList.size}") Log.d(TAG, "$title program ${program.dataListList.size}")
} }
} else { } else {
@ -657,6 +657,31 @@ object Request {
}) })
} }
fun fetchFEPG(tvViewModel: TVViewModel) {
val title = tvViewModel.title.value
fAuthService.getEPG(tvViewModel.pid.value!!, getDateFormat("yyyyMMdd"))
.enqueue(object : Callback<List<FEPG>> {
override fun onResponse(
call: Call<List<FEPG>>,
response: Response<List<FEPG>>
) {
if (response.isSuccessful) {
val program = response.body()
if (program != null) {
tvViewModel.addFEPG(program)
Log.d(TAG, "$title program ${program.size}")
}
} else {
Log.w(TAG, "$title program error")
}
}
override fun onFailure(call: Call<List<FEPG>>, t: Throwable) {
Log.e(TAG, "$title program request failed $t")
}
})
}
private fun encryptTripleDES(key: ByteArray, iv: ByteArray): String { private fun encryptTripleDES(key: ByteArray, iv: ByteArray): String {
return try { return try {
val keySpec = SecretKeySpec(key, "DESede") val keySpec = SecretKeySpec(key, "DESede")

File diff suppressed because it is too large Load Diff

@ -3,6 +3,7 @@ package com.lizongying.mytv.api
import retrofit2.Call import retrofit2.Call
import retrofit2.http.GET import retrofit2.http.GET
import retrofit2.http.Header import retrofit2.http.Header
import retrofit2.http.Path
import retrofit2.http.Query import retrofit2.http.Query
interface FAuthService { interface FAuthService {
@ -12,4 +13,11 @@ interface FAuthService {
@Query("live_id") live_id: String = "", @Query("live_id") live_id: String = "",
@Query("live_qa") live_qa: String = "", @Query("live_qa") live_qa: String = "",
): Call<FAuth> ): Call<FAuth>
@GET("api/v3/live/{liveId}/resources")
fun getEPG(
@Path("liveId") liveId: String,
@Query("date") date: String,
@Query("dir") dir: String = "asc"
): Call<List<FEPG>>
} }

@ -0,0 +1,7 @@
package com.lizongying.mytv.api
data class FEPG(
val title: String,
val event_time: String,
)

@ -0,0 +1,7 @@
package com.lizongying.mytv.models
data class EPG(
val title: String,
val beginTime: Int,
)

@ -11,8 +11,10 @@ import androidx.media3.common.util.UnstableApi
import androidx.media3.datasource.DefaultHttpDataSource import androidx.media3.datasource.DefaultHttpDataSource
import androidx.media3.exoplayer.hls.HlsMediaSource import androidx.media3.exoplayer.hls.HlsMediaSource
import com.lizongying.mytv.TV import com.lizongying.mytv.TV
import com.lizongying.mytv.Utils.getDateTimestamp import com.lizongying.mytv.api.FEPG
import com.lizongying.mytv.proto.Ysp.cn.yangshipin.omstv.common.proto.programModel.Program import com.lizongying.mytv.proto.Ysp.cn.yangshipin.omstv.common.proto.programModel.Program
import java.text.SimpleDateFormat
import java.util.TimeZone
class TVViewModel(private var tv: TV) : ViewModel() { class TVViewModel(private var tv: TV) : ViewModel() {
@ -33,9 +35,9 @@ class TVViewModel(private var tv: TV) : ViewModel() {
val programId: LiveData<String> val programId: LiveData<String>
get() = _programId get() = _programId
private var _program = MutableLiveData<MutableList<Program>>() private var _epg = MutableLiveData<MutableList<EPG>>()
val program: LiveData<MutableList<Program>> val epg: LiveData<MutableList<EPG>>
get() = _program get() = _epg
private val _id = MutableLiveData<Int>() private val _id = MutableLiveData<Int>()
val id: LiveData<Int> val id: LiveData<Int>
@ -120,10 +122,8 @@ class TVViewModel(private var tv: TV) : ViewModel() {
_programId.value = tv.programId _programId.value = tv.programId
_pid.value = tv.pid _pid.value = tv.pid
_sid.value = tv.sid _sid.value = tv.sid
_program.value = mutableListOf()
} }
fun getRowPosition(): Int { fun getRowPosition(): Int {
return rowPosition return rowPosition
} }
@ -152,37 +152,23 @@ class TVViewModel(private var tv: TV) : ViewModel() {
return tv return tv
} }
fun getProgramOne(): Program? { fun addYEPG(p: MutableList<Program>) {
val programNew = _epg.value = p.map { EPG(it.name, it.st.toInt()) }.toMutableList()
(_program.value?.filter { it.et > getDateTimestamp() })?.toMutableList()
if (programNew != null && _program.value != programNew) {
_program.value = programNew
}
if (_program.value!!.isEmpty()) {
return null
}
return _program.value?.first()
} }
fun addProgram(p: MutableList<Program>) { private fun formatFTime(s: String): Int {
val timestamp = getDateTimestamp() val dateFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss")
dateFormat.timeZone = TimeZone.getTimeZone("UTC")
// after now & not empty & different val date = dateFormat.parse(s.substring(0, 19))
val p1 = (p.filter { it.et > timestamp }).toMutableList() if (date != null) {
if (p1.isEmpty() || _program.value == p1) { return (date.time / 1000).toInt()
return
}
if (_program.value!!.isEmpty()) {
_program.value = p1
} else {
_program.value =
((_program.value?.filter { it.et > timestamp && it.st < p1.first().st })?.plus(
p1
))?.toMutableList()
} }
return 0
} }
fun addFEPG(p: List<FEPG>) {
_epg.value = p.map { EPG(it.title, formatFTime(it.event_time)) }.toMutableList()
}
private var mHeaders: Map<String, String>? = mapOf() private var mHeaders: Map<String, String>? = mapOf()

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

@ -130,7 +130,7 @@
"programId": "600004078", "programId": "600004078",
"needToken": true, "needToken": true,
"mustToken": false, "mustToken": false,
"title": "CCTV9 录", "title": "CCTV9 录",
"videoUrl": [ "videoUrl": [
"http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226197/index.m3u8" "http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226197/index.m3u8"
] ]

Loading…
Cancel
Save