2023-12-15 13:04:32 +08:00
|
|
|
package com.lizongying.mytv
|
|
|
|
|
|
|
|
|
|
import android.content.Context
|
2023-12-15 18:12:11 +08:00
|
|
|
import android.util.Base64
|
2023-12-15 13:04:32 +08:00
|
|
|
import android.util.Log
|
|
|
|
|
import com.lizongying.mytv.api.ApiClient
|
|
|
|
|
import com.lizongying.mytv.api.LiveInfo
|
|
|
|
|
import com.lizongying.mytv.api.LiveInfoRequest
|
|
|
|
|
import com.lizongying.mytv.api.ProtoClient
|
|
|
|
|
import com.lizongying.mytv.api.YSP
|
|
|
|
|
import com.lizongying.mytv.api.YSPApiService
|
|
|
|
|
import com.lizongying.mytv.api.YSPProtoService
|
|
|
|
|
import com.lizongying.mytv.models.TVViewModel
|
|
|
|
|
import com.lizongying.mytv.proto.Ysp.cn.yangshipin.oms.common.proto.pageModel
|
|
|
|
|
import retrofit2.Call
|
|
|
|
|
import retrofit2.Callback
|
|
|
|
|
import retrofit2.Response
|
2023-12-15 18:12:11 +08:00
|
|
|
import javax.crypto.Cipher
|
|
|
|
|
import javax.crypto.spec.IvParameterSpec
|
|
|
|
|
import javax.crypto.spec.SecretKeySpec
|
2023-12-15 13:04:32 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
class Request(var context: Context) {
|
|
|
|
|
private var ysp: YSP? = null
|
|
|
|
|
private var yspApiService: YSPApiService? = null
|
|
|
|
|
private var yspProtoService: YSPProtoService? = null
|
|
|
|
|
|
|
|
|
|
private var mapping = mapOf(
|
|
|
|
|
"CCTV4K" to "CCTV4K",
|
|
|
|
|
"CCTV1" to "CCTV1 综合",
|
|
|
|
|
"CCTV2" to "CCTV2 财经",
|
|
|
|
|
"CCTV4" to "CCTV4 中文国际",
|
|
|
|
|
"CCTV5" to "CCTV5 体育",
|
|
|
|
|
"CCTV5+" to "CCTV5+ 体育赛事",
|
|
|
|
|
"CCTV7" to "CCTV7 国防军事",
|
|
|
|
|
"CCTV9" to "CCTV9 记录",
|
|
|
|
|
"CCTV10" to "CCTV10 科教",
|
|
|
|
|
"CCTV11" to "CCTV11 戏曲",
|
|
|
|
|
"CCTV12" to "CCTV12 社会与法",
|
2023-12-18 10:12:52 +08:00
|
|
|
"CCTV13" to "CCTV13 新闻",
|
2023-12-15 13:04:32 +08:00
|
|
|
"CCTV14" to "CCTV14 少儿",
|
|
|
|
|
"CCTV15" to "CCTV15 音乐",
|
|
|
|
|
"CCTV16-HD" to "CCTV16 奥林匹克",
|
|
|
|
|
"CCTV17" to "CCTV17 农业农村",
|
|
|
|
|
"CGTN" to "CGTN",
|
2023-12-18 10:12:52 +08:00
|
|
|
"CGTN外语纪录频道" to "CGTN 纪录频道",
|
2023-12-15 13:04:32 +08:00
|
|
|
"CGTN法语频道" to "CGTN 法语频道",
|
|
|
|
|
"CGTN俄语频道" to "CGTN 俄语频道",
|
|
|
|
|
"CGTN阿拉伯语频道" to "CGTN 阿拉伯语频道",
|
|
|
|
|
"CGTN西班牙语频道" to "CGTN 西班牙语频道",
|
|
|
|
|
|
|
|
|
|
"东方卫视" to "东方卫视",
|
|
|
|
|
"湖南卫视" to "湖南卫视",
|
|
|
|
|
"湖北卫视" to "湖北卫视",
|
|
|
|
|
"辽宁卫视" to "辽宁卫视",
|
|
|
|
|
"江苏卫视" to "江苏卫视",
|
|
|
|
|
"江西卫视" to "江西卫视",
|
|
|
|
|
"山东卫视" to "山东卫视",
|
|
|
|
|
"广东卫视" to "广东卫视",
|
|
|
|
|
"广西卫视" to "广西卫视",
|
|
|
|
|
"重庆卫视" to "重庆卫视",
|
|
|
|
|
"河南卫视" to "河南卫视",
|
|
|
|
|
"河北卫视" to "河北卫视",
|
|
|
|
|
"贵州卫视" to "贵州卫视",
|
|
|
|
|
"北京卫视" to "北京卫视",
|
|
|
|
|
"黑龙江卫视" to "黑龙江卫视",
|
|
|
|
|
"浙江卫视" to "浙江卫视",
|
|
|
|
|
"安徽卫视" to "安徽卫视",
|
|
|
|
|
"深圳卫视" to "深圳卫视",
|
|
|
|
|
"四川卫视" to "四川卫视",
|
|
|
|
|
"福建东南卫视" to "东南卫视",
|
|
|
|
|
"海南卫视" to "海南卫视",
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
init {
|
|
|
|
|
if (context is MainActivity) {
|
|
|
|
|
ysp = YSP(context)
|
|
|
|
|
}
|
|
|
|
|
yspApiService = ApiClient().yspApiService
|
|
|
|
|
yspProtoService = ProtoClient().yspProtoService
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fun fetchData(tvModel: TVViewModel) {
|
|
|
|
|
val data = ysp?.switch(tvModel)
|
2023-12-18 10:12:52 +08:00
|
|
|
val title = tvModel.getTV().title
|
2023-12-15 13:04:32 +08:00
|
|
|
|
|
|
|
|
val request = data?.let { LiveInfoRequest(it) }
|
|
|
|
|
request?.let { yspApiService?.getLiveInfo(it) }
|
|
|
|
|
?.enqueue(object : Callback<LiveInfo> {
|
|
|
|
|
override fun onResponse(call: Call<LiveInfo>, response: Response<LiveInfo>) {
|
|
|
|
|
if (response.isSuccessful) {
|
|
|
|
|
val liveInfo = response.body()
|
|
|
|
|
if (liveInfo?.data?.playurl != null) {
|
2023-12-15 18:12:11 +08:00
|
|
|
val chanll = liveInfo.data.chanll
|
|
|
|
|
val decodedBytes = Base64.decode(
|
|
|
|
|
chanll.substring(9, chanll.length - 3),
|
|
|
|
|
Base64.DEFAULT
|
|
|
|
|
)
|
|
|
|
|
val decodedString = String(decodedBytes)
|
|
|
|
|
val regex = Regex("""des_key = "([^"]+).+var des_iv = "([^"]+)""")
|
|
|
|
|
val matchResult = regex.find(decodedString)
|
|
|
|
|
if (matchResult != null) {
|
|
|
|
|
val (key, iv) = matchResult.destructured
|
2023-12-18 10:12:52 +08:00
|
|
|
val keyBytes = Base64.decode(key, Base64.DEFAULT)
|
|
|
|
|
val ivBytes = Base64.decode(iv, Base64.DEFAULT)
|
|
|
|
|
val url = liveInfo.data.playurl + "&revoi=" + encryptTripleDES(
|
2023-12-16 08:19:02 +08:00
|
|
|
keyBytes + byteArrayOf(0, 0, 0, 0, 0, 0, 0, 0),
|
2023-12-15 18:12:11 +08:00
|
|
|
ivBytes
|
2023-12-16 08:19:02 +08:00
|
|
|
).uppercase()
|
2023-12-18 10:12:52 +08:00
|
|
|
Log.i(TAG, "$title url $url")
|
|
|
|
|
tvModel.addVideoUrl(url)
|
|
|
|
|
} else {
|
|
|
|
|
Log.e(TAG, "$title key error")
|
|
|
|
|
tvModel.firstSource()
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
Log.e(TAG, "$title url error")
|
|
|
|
|
tvModel.firstSource()
|
2023-12-15 13:04:32 +08:00
|
|
|
}
|
2023-12-18 10:12:52 +08:00
|
|
|
} else {
|
|
|
|
|
Log.e(TAG, "$title status error")
|
|
|
|
|
tvModel.firstSource()
|
2023-12-15 13:04:32 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override fun onFailure(call: Call<LiveInfo>, t: Throwable) {
|
2023-12-18 10:12:52 +08:00
|
|
|
Log.e(TAG, "${tvModel.getTV().title} request error")
|
|
|
|
|
tvModel.firstSource()
|
2023-12-15 13:04:32 +08:00
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fun fetchPage() {
|
|
|
|
|
yspProtoService?.getPage()?.enqueue(object : Callback<pageModel.Response> {
|
|
|
|
|
override fun onResponse(
|
|
|
|
|
call: Call<pageModel.Response>,
|
|
|
|
|
response: Response<pageModel.Response>
|
|
|
|
|
) {
|
|
|
|
|
if (response.isSuccessful) {
|
|
|
|
|
val body = response.body()
|
|
|
|
|
|
|
|
|
|
if (body?.data?.feedModuleListCount == 1) {
|
|
|
|
|
for (item in body.data?.feedModuleListList!![0]?.dataTvChannelListList!!) {
|
|
|
|
|
if (item.isVip && !item.isLimitedFree) {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
Log.i(
|
|
|
|
|
TAG,
|
|
|
|
|
"${item.channelName} ,${item.tvLogo},${item.pid},${item.streamId}"
|
|
|
|
|
)
|
|
|
|
|
var channelType = "央视频道"
|
|
|
|
|
if (item?.channelType === "weishi") {
|
|
|
|
|
channelType = "地方频道"
|
|
|
|
|
}
|
|
|
|
|
if (!mapping.containsKey(item.channelName)) {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
val tv = TVList.list[channelType]?.get(mapping[item.channelName])
|
|
|
|
|
if (tv != null) {
|
|
|
|
|
tv.logo = item.tvLogo
|
|
|
|
|
tv.pid = item.pid
|
|
|
|
|
tv.sid = item.streamId
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override fun onFailure(call: Call<pageModel.Response>, t: Throwable) {
|
|
|
|
|
Log.e(TAG, "Page request failed", t)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fun fetchProgram(tvModel: TVViewModel) {
|
|
|
|
|
yspProtoService?.getProgram("", "")?.enqueue(object : Callback<LiveInfo> {
|
|
|
|
|
override fun onResponse(call: Call<LiveInfo>, response: Response<LiveInfo>) {
|
|
|
|
|
if (response.isSuccessful) {
|
|
|
|
|
val liveInfo = response.body()
|
|
|
|
|
Log.i(TAG, "${liveInfo?.data?.playurl}")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override fun onFailure(call: Call<LiveInfo>, t: Throwable) {
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-15 18:12:11 +08:00
|
|
|
private fun encryptTripleDES(key: ByteArray, iv: ByteArray): String {
|
2023-12-16 08:19:02 +08:00
|
|
|
var plaintext =
|
2023-12-15 18:12:11 +08:00
|
|
|
"""{"mver":"1","subver":"1.2","host":"www.yangshipin.cn/#/tv/home?pid=","referer":"","canvas":"YSPANGLE(Apple,AppleM1Pro,OpenGL4.1)"}"""
|
|
|
|
|
return try {
|
|
|
|
|
val keySpec = SecretKeySpec(key, "DESede")
|
|
|
|
|
val ivSpec = IvParameterSpec(iv)
|
2023-12-16 08:19:02 +08:00
|
|
|
val cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding")
|
2023-12-15 18:12:11 +08:00
|
|
|
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec)
|
|
|
|
|
val encryptedBytes = cipher.doFinal(plaintext.toByteArray())
|
2023-12-16 08:19:02 +08:00
|
|
|
return encryptedBytes.let { it -> it.joinToString("") { "%02x".format(it) } }
|
2023-12-15 18:12:11 +08:00
|
|
|
} catch (e: Exception) {
|
|
|
|
|
e.printStackTrace()
|
|
|
|
|
""
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-15 13:04:32 +08:00
|
|
|
companion object {
|
|
|
|
|
private const val TAG = "Request"
|
|
|
|
|
}
|
|
|
|
|
}
|