fix 5mins
This commit is contained in:
parent
5ea45fdc02
commit
262c92e0ad
|
|
@ -0,0 +1,23 @@
|
||||||
|
package com.lizongying.mytv
|
||||||
|
|
||||||
|
import androidx.media3.common.C
|
||||||
|
import androidx.media3.common.util.UnstableApi
|
||||||
|
import androidx.media3.exoplayer.upstream.DefaultLoadErrorHandlingPolicy
|
||||||
|
|
||||||
|
|
||||||
|
@UnstableApi
|
||||||
|
class CustomLoadErrorHandlingPolicy(private val minimumLoadableRetryCount: Int) :
|
||||||
|
DefaultLoadErrorHandlingPolicy(minimumLoadableRetryCount) {
|
||||||
|
|
||||||
|
override fun getMinimumLoadableRetryCount(dataType: Int): Int {
|
||||||
|
return if (minimumLoadableRetryCount == -1) {
|
||||||
|
if (dataType == C.DATA_TYPE_MEDIA_PROGRESSIVE_LIVE) {
|
||||||
|
DEFAULT_MIN_LOADABLE_RETRY_COUNT_PROGRESSIVE_LIVE
|
||||||
|
} else {
|
||||||
|
DEFAULT_MIN_LOADABLE_RETRY_COUNT
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
minimumLoadableRetryCount
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -38,6 +38,22 @@ open class ExoPlayerAdapter(private var mContext: Context?) : PlayerAdapter() {
|
||||||
|
|
||||||
var mBufferingStart = false
|
var mBufferingStart = false
|
||||||
|
|
||||||
|
|
||||||
|
private var mMinimumLoadableRetryCount = 3
|
||||||
|
|
||||||
|
|
||||||
|
private var mPlayerErrorListener: PlayerErrorListener? = null
|
||||||
|
|
||||||
|
init {
|
||||||
|
mPlayer?.playWhenReady = true
|
||||||
|
|
||||||
|
if (mPlayerErrorListener == null) {
|
||||||
|
mPlayerErrorListener = PlayerErrorListener()
|
||||||
|
mPlayer?.addListener(mPlayerErrorListener!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
open fun notifyBufferingStartEnd() {
|
open fun notifyBufferingStartEnd() {
|
||||||
callback.onBufferingStateChanged(
|
callback.onBufferingStateChanged(
|
||||||
this@ExoPlayerAdapter,
|
this@ExoPlayerAdapter,
|
||||||
|
|
@ -178,14 +194,19 @@ open class ExoPlayerAdapter(private var mContext: Context?) : PlayerAdapter() {
|
||||||
return mBufferedProgress
|
return mBufferedProgress
|
||||||
}
|
}
|
||||||
|
|
||||||
private var mPlayerErrorListener: PlayerErrorListener? = null
|
|
||||||
|
|
||||||
private inner class PlayerErrorListener : Player.Listener {
|
private inner class PlayerErrorListener : Player.Listener {
|
||||||
override fun onPlayerError(error: PlaybackException) {
|
override fun onPlayerError(error: PlaybackException) {
|
||||||
callback.onError(this@ExoPlayerAdapter, error.errorCode, error.message)
|
callback.onError(this@ExoPlayerAdapter, error.errorCode, error.message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private var mHeaders: Map<String, String>? = mapOf()
|
||||||
|
|
||||||
|
fun setHeaders(headers: Map<String, String>) {
|
||||||
|
mHeaders = headers
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the media source of the player witha given URI.
|
* Sets the media source of the player witha given URI.
|
||||||
*
|
*
|
||||||
|
|
@ -193,46 +214,43 @@ open class ExoPlayerAdapter(private var mContext: Context?) : PlayerAdapter() {
|
||||||
* otherwise.
|
* otherwise.
|
||||||
* @see MediaPlayer.setDataSource
|
* @see MediaPlayer.setDataSource
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@OptIn(UnstableApi::class)
|
||||||
open fun setDataSource(uri: Uri?): Boolean {
|
open fun setDataSource(uri: Uri?): Boolean {
|
||||||
if (if (mMediaSourceUri != null) mMediaSourceUri == uri else uri == null) {
|
if (if (mMediaSourceUri != null) mMediaSourceUri == uri else uri == null) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
mMediaSourceUri = uri
|
mMediaSourceUri = uri
|
||||||
prepareMediaForPlaying()
|
|
||||||
|
|
||||||
mPlayer?.playWhenReady = true
|
|
||||||
|
|
||||||
if (mPlayerErrorListener == null) {
|
|
||||||
mPlayerErrorListener = PlayerErrorListener()
|
|
||||||
mPlayer?.addListener(mPlayerErrorListener!!)
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
private var mHeaders: Map<String, String>? = mapOf()
|
|
||||||
|
|
||||||
fun setHeaders(headers: Map<String, String>) {
|
|
||||||
mHeaders = headers
|
|
||||||
}
|
|
||||||
|
|
||||||
@OptIn(UnstableApi::class)
|
|
||||||
private fun prepareMediaForPlaying() {
|
|
||||||
reset()
|
|
||||||
try {
|
|
||||||
if (mMediaSourceUri != null) {
|
|
||||||
val httpDataSource = DefaultHttpDataSource.Factory()
|
val httpDataSource = DefaultHttpDataSource.Factory()
|
||||||
mHeaders?.let { httpDataSource.setDefaultRequestProperties(it) }
|
mHeaders?.let { httpDataSource.setDefaultRequestProperties(it) }
|
||||||
|
|
||||||
val hlsMediaSource =
|
val hlsMediaSource =
|
||||||
HlsMediaSource.Factory(httpDataSource).createMediaSource(
|
HlsMediaSource.Factory(httpDataSource).setLoadErrorHandlingPolicy(
|
||||||
|
CustomLoadErrorHandlingPolicy(mMinimumLoadableRetryCount)
|
||||||
|
).createMediaSource(
|
||||||
MediaItem.fromUri(
|
MediaItem.fromUri(
|
||||||
mMediaSourceUri!!
|
mMediaSourceUri!!
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
mPlayer?.setMediaSource(hlsMediaSource)
|
prepareMediaForPlaying(hlsMediaSource)
|
||||||
} else {
|
return true
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(UnstableApi::class)
|
||||||
|
open fun setDataSource(hlsMediaSource: HlsMediaSource): Boolean {
|
||||||
|
prepareMediaForPlaying(hlsMediaSource)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setMinimumLoadableRetryCount(minimumLoadableRetryCount: Int) {
|
||||||
|
mMinimumLoadableRetryCount = minimumLoadableRetryCount
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(UnstableApi::class)
|
||||||
|
private fun prepareMediaForPlaying(hlsMediaSource: HlsMediaSource) {
|
||||||
|
try {
|
||||||
|
mPlayer?.setMediaSource(hlsMediaSource)
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
throw RuntimeException(e)
|
throw RuntimeException(e)
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,11 @@ class PlaybackFragment : VideoSupportFragment() {
|
||||||
|
|
||||||
view?.isFocusable = false
|
view?.isFocusable = false
|
||||||
view?.isFocusableInTouchMode = false
|
view?.isFocusableInTouchMode = false
|
||||||
|
|
||||||
|
val glueHost = VideoSupportFragmentGlueHost(this@PlaybackFragment)
|
||||||
|
mTransportControlGlue = PlaybackControlGlue(activity, playerAdapter)
|
||||||
|
mTransportControlGlue.host = glueHost
|
||||||
|
mTransportControlGlue.playWhenPrepared()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showControlsOverlay(runAnimation: Boolean) {
|
override fun showControlsOverlay(runAnimation: Boolean) {
|
||||||
|
|
@ -44,12 +49,10 @@ class PlaybackFragment : VideoSupportFragment() {
|
||||||
|
|
||||||
lastVideoUrl = videoUrl
|
lastVideoUrl = videoUrl
|
||||||
|
|
||||||
val glueHost = VideoSupportFragmentGlueHost(this@PlaybackFragment)
|
|
||||||
mTransportControlGlue = PlaybackControlGlue(activity, playerAdapter)
|
|
||||||
mTransportControlGlue.host = glueHost
|
|
||||||
mTransportControlGlue.playWhenPrepared()
|
|
||||||
|
|
||||||
playerAdapter?.callback = PlayerCallback(tvModel)
|
playerAdapter?.callback = PlayerCallback(tvModel)
|
||||||
|
if (tvModel.ysp() != null) {
|
||||||
|
playerAdapter?.setMinimumLoadableRetryCount(0)
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
playerAdapter?.setDataSource(Uri.parse(videoUrl))
|
playerAdapter?.setDataSource(Uri.parse(videoUrl))
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,18 @@
|
||||||
package com.lizongying.mytv
|
package com.lizongying.mytv
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.Looper
|
||||||
import android.util.Base64
|
import android.util.Base64
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import com.lizongying.mytv.api.ApiClient
|
import com.lizongying.mytv.api.ApiClient
|
||||||
|
import com.lizongying.mytv.api.BtraceClient
|
||||||
import com.lizongying.mytv.api.LiveInfo
|
import com.lizongying.mytv.api.LiveInfo
|
||||||
import com.lizongying.mytv.api.LiveInfoRequest
|
import com.lizongying.mytv.api.LiveInfoRequest
|
||||||
import com.lizongying.mytv.api.ProtoClient
|
import com.lizongying.mytv.api.ProtoClient
|
||||||
import com.lizongying.mytv.api.YSP
|
import com.lizongying.mytv.api.YSP
|
||||||
import com.lizongying.mytv.api.YSPApiService
|
import com.lizongying.mytv.api.YSPApiService
|
||||||
|
import com.lizongying.mytv.api.YSPBtraceService
|
||||||
import com.lizongying.mytv.api.YSPProtoService
|
import com.lizongying.mytv.api.YSPProtoService
|
||||||
import com.lizongying.mytv.models.TVViewModel
|
import com.lizongying.mytv.models.TVViewModel
|
||||||
import com.lizongying.mytv.proto.Ysp.cn.yangshipin.oms.common.proto.pageModel
|
import com.lizongying.mytv.proto.Ysp.cn.yangshipin.oms.common.proto.pageModel
|
||||||
|
|
@ -27,8 +31,12 @@ import javax.crypto.spec.SecretKeySpec
|
||||||
class Request(var context: Context) {
|
class Request(var context: Context) {
|
||||||
private var ysp: YSP? = null
|
private var ysp: YSP? = null
|
||||||
private var yspApiService: YSPApiService? = null
|
private var yspApiService: YSPApiService? = null
|
||||||
|
private var yspBtraceService: YSPBtraceService? = null
|
||||||
private var yspProtoService: YSPProtoService? = null
|
private var yspProtoService: YSPProtoService? = null
|
||||||
|
|
||||||
|
private val handler = Handler(Looper.getMainLooper())
|
||||||
|
private lateinit var myRunnable: MyRunnable
|
||||||
|
|
||||||
private var mapping = mapOf(
|
private var mapping = mapOf(
|
||||||
"CCTV4K" to "CCTV4K 超高清",
|
"CCTV4K" to "CCTV4K 超高清",
|
||||||
"CCTV1" to "CCTV1 综合",
|
"CCTV1" to "CCTV1 综合",
|
||||||
|
|
@ -81,10 +89,16 @@ class Request(var context: Context) {
|
||||||
ysp = YSP(context)
|
ysp = YSP(context)
|
||||||
}
|
}
|
||||||
yspApiService = ApiClient().yspApiService
|
yspApiService = ApiClient().yspApiService
|
||||||
|
yspBtraceService = BtraceClient().yspBtraceService
|
||||||
yspProtoService = ProtoClient().yspProtoService
|
yspProtoService = ProtoClient().yspProtoService
|
||||||
}
|
}
|
||||||
|
|
||||||
fun fetchData(tvModel: TVViewModel) {
|
fun fetchData(tvModel: TVViewModel) {
|
||||||
|
if (::myRunnable.isInitialized) {
|
||||||
|
handler.removeCallbacks(myRunnable)
|
||||||
|
}
|
||||||
|
|
||||||
|
tvModel.seq = 0
|
||||||
val data = ysp?.switch(tvModel)
|
val data = ysp?.switch(tvModel)
|
||||||
val title = tvModel.title.value
|
val title = tvModel.title.value
|
||||||
|
|
||||||
|
|
@ -114,6 +128,9 @@ class Request(var context: Context) {
|
||||||
Log.i(TAG, "$title url $url")
|
Log.i(TAG, "$title url $url")
|
||||||
tvModel.addVideoUrl(url)
|
tvModel.addVideoUrl(url)
|
||||||
tvModel.allReady()
|
tvModel.allReady()
|
||||||
|
|
||||||
|
myRunnable = MyRunnable(tvModel)
|
||||||
|
handler.post(myRunnable)
|
||||||
} else {
|
} else {
|
||||||
Log.e(TAG, "$title key error")
|
Log.e(TAG, "$title key error")
|
||||||
tvModel.firstSource()
|
tvModel.firstSource()
|
||||||
|
|
@ -135,6 +152,49 @@ class Request(var context: Context) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inner class MyRunnable(private val tvModel: TVViewModel) : Runnable {
|
||||||
|
override fun run() {
|
||||||
|
fetchBtrace(tvModel)
|
||||||
|
handler.postDelayed(this, 60000)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun fetchBtrace(tvModel: TVViewModel) {
|
||||||
|
val title = tvModel.title.value
|
||||||
|
|
||||||
|
val guid = ysp?.getGuid()!!
|
||||||
|
val pid = tvModel.pid.value!!
|
||||||
|
val sid = tvModel.sid.value!!
|
||||||
|
yspBtraceService?.kvcollect(
|
||||||
|
c_timestamp = ysp?.generateGuid()!!,
|
||||||
|
guid = guid,
|
||||||
|
c_guid = guid,
|
||||||
|
prog = sid,
|
||||||
|
viewid = sid,
|
||||||
|
fpid = pid,
|
||||||
|
livepid = pid,
|
||||||
|
sUrl = "https://www.yangshipin.cn/#/tv/home?pid=$pid",
|
||||||
|
playno = ysp?.getRand()!!,
|
||||||
|
ftime = getCurrentDate2(),
|
||||||
|
seq = tvModel.seq.toString(),
|
||||||
|
)
|
||||||
|
?.enqueue(object : Callback<Void> {
|
||||||
|
override fun onResponse(call: Call<Void>, response: Response<Void>) {
|
||||||
|
if (response.isSuccessful) {
|
||||||
|
Log.i(TAG, "$title kvcollect success")
|
||||||
|
} else {
|
||||||
|
Log.e(TAG, "$title status error")
|
||||||
|
tvModel.firstSource()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFailure(call: Call<Void>, t: Throwable) {
|
||||||
|
Log.e(TAG, "$title btrace error")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
tvModel.seq++
|
||||||
|
}
|
||||||
|
|
||||||
fun fetchPage() {
|
fun fetchPage() {
|
||||||
yspProtoService?.getPage()?.enqueue(object : Callback<pageModel.Response> {
|
yspProtoService?.getPage()?.enqueue(object : Callback<pageModel.Response> {
|
||||||
override fun onResponse(
|
override fun onResponse(
|
||||||
|
|
@ -184,6 +244,12 @@ class Request(var context: Context) {
|
||||||
return formatter.format(currentDate)
|
return formatter.format(currentDate)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun getCurrentDate2(): String {
|
||||||
|
val currentDate = Date()
|
||||||
|
val formatter = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA)
|
||||||
|
return formatter.format(currentDate)
|
||||||
|
}
|
||||||
|
|
||||||
fun fetchProgram(tvModel: TVViewModel) {
|
fun fetchProgram(tvModel: TVViewModel) {
|
||||||
yspProtoService?.getProgram(tvModel.programId.value!!, getCurrentDate())
|
yspProtoService?.getProgram(tvModel.programId.value!!, getCurrentDate())
|
||||||
?.enqueue(object : Callback<epgProgramModel.Response> {
|
?.enqueue(object : Callback<epgProgramModel.Response> {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
package com.lizongying.mytv.api
|
||||||
|
|
||||||
|
|
||||||
|
import retrofit2.Retrofit
|
||||||
|
import retrofit2.converter.gson.GsonConverterFactory
|
||||||
|
|
||||||
|
|
||||||
|
class BtraceClient {
|
||||||
|
private val yspUrl = "https://btrace.yangshipin.cn/"
|
||||||
|
|
||||||
|
val yspBtraceService: YSPBtraceService by lazy {
|
||||||
|
Retrofit.Builder()
|
||||||
|
.baseUrl(yspUrl)
|
||||||
|
.addConverterFactory(GsonConverterFactory.create())
|
||||||
|
.build().create(YSPBtraceService::class.java)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -85,7 +85,7 @@ class YSP(var context: Context) {
|
||||||
return (Date().time / 1000).toString()
|
return (Date().time / 1000).toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun generateGuid(): String {
|
fun generateGuid(): String {
|
||||||
val timestamp = (System.currentTimeMillis()).toString(36)
|
val timestamp = (System.currentTimeMillis()).toString(36)
|
||||||
val originalString = Math.random().toString()
|
val originalString = Math.random().toString()
|
||||||
val resultString = if (originalString.startsWith("0.")) {
|
val resultString = if (originalString.startsWith("0.")) {
|
||||||
|
|
@ -97,7 +97,7 @@ class YSP(var context: Context) {
|
||||||
return timestamp + "_" + randomPart
|
return timestamp + "_" + randomPart
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getGuid(): String {
|
fun getGuid(): String {
|
||||||
var guid = sharedPref?.getString("guid", "")
|
var guid = sharedPref?.getString("guid", "")
|
||||||
if (guid == null || guid.length < 18) {
|
if (guid == null || guid.length < 18) {
|
||||||
guid = generateGuid()
|
guid = generateGuid()
|
||||||
|
|
@ -109,7 +109,7 @@ class YSP(var context: Context) {
|
||||||
return guid
|
return guid
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getRand(): String {
|
fun getRand(): String {
|
||||||
var n = ""
|
var n = ""
|
||||||
val e = "ABCDEFGHIJKlMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
|
val e = "ABCDEFGHIJKlMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
|
||||||
val r = e.length
|
val r = e.length
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,71 @@
|
||||||
|
package com.lizongying.mytv.api
|
||||||
|
|
||||||
|
import retrofit2.Call
|
||||||
|
import retrofit2.http.Field
|
||||||
|
import retrofit2.http.FormUrlEncoded
|
||||||
|
import retrofit2.http.Headers
|
||||||
|
import retrofit2.http.POST
|
||||||
|
import retrofit2.http.Path
|
||||||
|
import retrofit2.http.Query
|
||||||
|
|
||||||
|
|
||||||
|
interface YSPBtraceService {
|
||||||
|
@FormUrlEncoded
|
||||||
|
@POST("kvcollect")
|
||||||
|
@Headers(
|
||||||
|
"content-type: application/x-www-form-urlencoded",
|
||||||
|
"referer: https://www.yangshipin.cn/",
|
||||||
|
)
|
||||||
|
fun kvcollect(
|
||||||
|
@Query("BossId") BossId: String = "2727",
|
||||||
|
@Query("c_timestamp") c_timestamp: String = "",
|
||||||
|
@Field("Pwd") Pwd: String = "1424084450",
|
||||||
|
@Field("fpid") fpid: String = "",
|
||||||
|
@Field("livepid") livepid: String = "",
|
||||||
|
@Field("prd") prd: String = "60000",
|
||||||
|
@Field("ftime") ftime: String = "",
|
||||||
|
@Field("prog") prog: String = "",
|
||||||
|
@Field("playno") playno: String = "",
|
||||||
|
@Field("guid") guid: String = "",
|
||||||
|
@Field("hh_ua") hh_ua: String = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36",
|
||||||
|
@Field("cdn") cdn: String = "waibao",
|
||||||
|
@Field("platform") platform: String = "5910204",
|
||||||
|
@Field("errcode") errcode: String = "-",
|
||||||
|
@Field("sUrl") sUrl: String = "",
|
||||||
|
@Field("seq") seq: String = "",
|
||||||
|
@Field("login_type") login_type: String = "undefined",
|
||||||
|
@Field("open_id") open_id: String = "undefined",
|
||||||
|
@Field("openid") openid: String = "undefined",
|
||||||
|
@Field("defn") defn: String = "fhd",
|
||||||
|
@Field("durl") durl: String = "-",
|
||||||
|
@Field("sdtfrom") sdtfrom: String = "ysp_pc_01",
|
||||||
|
@Field("firstreport") firstreport: String = "0",
|
||||||
|
@Field("fplayerver") fplayerver: String = "89",
|
||||||
|
@Field("cmd") cmd: String = "263",
|
||||||
|
@Field("fact1") fact1: String = "ysp_pc_live_b",
|
||||||
|
@Field("sRef") sRef: String = "-",
|
||||||
|
@Field("viewid") viewid: String = "",
|
||||||
|
@Field("geturltime") geturltime: String = "0",
|
||||||
|
@Field("hc_openid") hc_openid: String = "undefined",
|
||||||
|
@Field("downspeed") downspeed: String = "10",
|
||||||
|
@Field("c_host") c_host: String = "www.yangshipin.cn",
|
||||||
|
@Field("c_pathname") c_pathname: String = "www.yangshipin.cn/",
|
||||||
|
@Field("c_url") c_url: String = "www.yangshipin.cn/",
|
||||||
|
@Field("c_channel") c_channel: String = "-",
|
||||||
|
@Field("c_referrer") c_referrer: String = "-",
|
||||||
|
@Field("c_ssize") c_ssize: String = "618",
|
||||||
|
@Field("c_ua") c_ua: String = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36",
|
||||||
|
@Field("c_os") c_os: String = "mac os",
|
||||||
|
@Field("c_osv") c_osv: String = "os10.15.7",
|
||||||
|
@Field("c_browser") c_browser: String = "chrome",
|
||||||
|
@Field("c_browserv") c_browserv: String = "chrome119",
|
||||||
|
@Field("c_dvendor") c_dvendor: String = "apple",
|
||||||
|
@Field("c_dmodel") c_dmodel: String = "macintosh",
|
||||||
|
@Field("c_dtype") c_dtype: String = "unkown",
|
||||||
|
@Field("c_city") c_city: String = "disabled",
|
||||||
|
@Field("c_nation") c_nation: String = "disabled",
|
||||||
|
@Field("c_province") c_province: String = "disabled",
|
||||||
|
@Field("c_guid") c_guid: String = "",
|
||||||
|
@Field("c_vuid") c_vuid: String = "-",
|
||||||
|
): Call<Void>
|
||||||
|
}
|
||||||
|
|
@ -1,9 +1,16 @@
|
||||||
package com.lizongying.mytv.models
|
package com.lizongying.mytv.models
|
||||||
|
|
||||||
|
import android.net.Uri
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import androidx.annotation.OptIn
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.ViewModel
|
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.CustomLoadErrorHandlingPolicy
|
||||||
import com.lizongying.mytv.TV
|
import com.lizongying.mytv.TV
|
||||||
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.util.Date
|
import java.util.Date
|
||||||
|
|
@ -242,6 +249,10 @@ class TVViewModel(private var tv: TV) : ViewModel() {
|
||||||
val ready: LiveData<Boolean>
|
val ready: LiveData<Boolean>
|
||||||
get() = _ready
|
get() = _ready
|
||||||
|
|
||||||
|
private var mMinimumLoadableRetryCount = 3
|
||||||
|
|
||||||
|
var seq = 0
|
||||||
|
|
||||||
fun addVideoUrl(url: String) {
|
fun addVideoUrl(url: String) {
|
||||||
if (_videoUrl.value?.isNotEmpty() == true) {
|
if (_videoUrl.value?.isNotEmpty() == true) {
|
||||||
if (_videoUrl.value!!.last().contains("cctv.cn")) {
|
if (_videoUrl.value!!.last().contains("cctv.cn")) {
|
||||||
|
|
@ -370,6 +381,32 @@ class TVViewModel(private var tv: TV) : ViewModel() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private var mHeaders: Map<String, String>? = mapOf()
|
||||||
|
|
||||||
|
fun setHeaders(headers: Map<String, String>) {
|
||||||
|
mHeaders = headers
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun setMinimumLoadableRetryCount(minimumLoadableRetryCount: Int) {
|
||||||
|
mMinimumLoadableRetryCount = minimumLoadableRetryCount
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(UnstableApi::class)
|
||||||
|
fun buildSource(videoUrl: String, mHeaders: Map<String, String>?): HlsMediaSource {
|
||||||
|
val httpDataSource = DefaultHttpDataSource.Factory()
|
||||||
|
mHeaders?.let { httpDataSource.setDefaultRequestProperties(it) }
|
||||||
|
|
||||||
|
return HlsMediaSource.Factory(httpDataSource).setLoadErrorHandlingPolicy(
|
||||||
|
CustomLoadErrorHandlingPolicy(mMinimumLoadableRetryCount)
|
||||||
|
).createMediaSource(
|
||||||
|
MediaItem.fromUri(
|
||||||
|
Uri.parse(videoUrl)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val TAG = "TVViewModel"
|
private const val TAG = "TVViewModel"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue