pull/731/head v1.6.0
Li ZongYing 2 years ago
parent d7a60531ab
commit 353dc0570f
  1. 1
      README.md
  2. BIN
      app/src/main/cpp/arm64-v8a/libnative.so
  3. BIN
      app/src/main/cpp/armeabi-v7a/libnative.so
  4. 2
      app/src/main/java/com/lizongying/mytv/Encryptor.kt
  5. 145
      app/src/main/java/com/lizongying/mytv/Request.kt
  6. 46
      app/src/main/java/com/lizongying/mytv/UpdateManager.kt
  7. 2
      app/src/main/java/com/lizongying/mytv/api/ApiClient.kt
  8. 37
      app/src/main/java/com/lizongying/mytv/api/Auth.kt
  9. 23
      app/src/main/java/com/lizongying/mytv/api/YSP.kt
  10. 14
      app/src/main/java/com/lizongying/mytv/api/YSPApiService.kt

@ -119,6 +119,7 @@ adb install my-tv.apk
* 获取系统时间
* 选中的图标比例能否相差更大
* 自动重连
* 节目增加预告
## 赞赏

@ -9,6 +9,8 @@ class Encryptor {
external fun hash(data: ByteArray): ByteArray?
external fun hash2(data: ByteArray): ByteArray?
companion object {
init {
System.loadLibrary("native")

@ -7,6 +7,8 @@ import android.util.Base64
import android.util.Log
import com.lizongying.mytv.Utils.getDateFormat
import com.lizongying.mytv.api.ApiClient
import com.lizongying.mytv.api.Auth
import com.lizongying.mytv.api.AuthRequest
import com.lizongying.mytv.api.Info
import com.lizongying.mytv.api.LiveInfo
import com.lizongying.mytv.api.LiveInfoRequest
@ -52,6 +54,84 @@ class Request {
}
var call: Call<LiveInfo>? = null
var callAuth: Call<Auth>? = null
private fun fetchAuth(tvModel: TVViewModel, cookie: String) {
callAuth?.cancel()
val title = tvModel.title.value
val data = ysp?.getAuthData(tvModel)
val request = data?.let { AuthRequest(it) }
callAuth = request?.let { yspApiService.getAuth("guid=${ysp?.getGuid()}; $cookie", it) }
callAuth?.enqueue(object : Callback<Auth> {
override fun onResponse(call: Call<Auth>, response: Response<Auth>) {
if (response.isSuccessful) {
val liveInfo = response.body()
if (liveInfo?.data?.token != null) {
Log.i(TAG, "token ${liveInfo.data.token}")
ysp?.token = liveInfo.data.token
fetchVideo(tvModel, cookie)
} else {
Log.e(TAG, "$title token error")
if (tvModel.retryTimes < tvModel.retryMaxTimes) {
tvModel.retryTimes++
if (tvModel.getTV().needToken) {
if (tvModel.tokenRetryTimes == tvModel.tokenRetryMaxTimes) {
if (!tvModel.getTV().mustToken) {
fetchAuth(tvModel, cookie)
}
} else {
token = ""
fetchAuth(tvModel)
}
} else {
fetchAuth(tvModel, cookie)
}
}
}
} else {
Log.e(TAG, "$title auth status error")
if (tvModel.retryTimes < tvModel.retryMaxTimes) {
tvModel.retryTimes++
if (tvModel.getTV().needToken) {
if (tvModel.tokenRetryTimes == tvModel.tokenRetryMaxTimes) {
if (!tvModel.getTV().mustToken) {
fetchAuth(tvModel, cookie)
}
} else {
token = ""
fetchAuth(tvModel)
}
} else {
fetchAuth(tvModel, cookie)
}
}
}
}
override fun onFailure(call: Call<Auth>, t: Throwable) {
Log.e(TAG, "$title auth request error $t")
if (tvModel.retryTimes < tvModel.retryMaxTimes) {
tvModel.retryTimes++
if (tvModel.getTV().needToken) {
if (tvModel.tokenRetryTimes == tvModel.tokenRetryMaxTimes) {
if (!tvModel.getTV().mustToken) {
fetchVideo(tvModel, cookie)
}
} else {
token = ""
fetchAuth(tvModel)
}
} else {
fetchAuth(tvModel, cookie)
}
}
}
})
}
fun fetchVideo(tvModel: TVViewModel, cookie: String) {
call?.cancel()
@ -64,7 +144,7 @@ class Request {
tvModel.seq = 0
val data = ysp?.switch(tvModel)
val request = data?.let { LiveInfoRequest(it) }
call = request?.let { yspApiService.getLiveInfo("guid=${ysp?.getGuid()}; $cookie", it) }
call = request?.let { yspApiService.getLiveInfo("guid=${ysp?.getGuid()}; $cookie", ysp!!.token, it) }
call?.enqueue(object : Callback<LiveInfo> {
override fun onResponse(call: Call<LiveInfo>, response: Response<LiveInfo>) {
@ -175,6 +255,53 @@ class Request {
})
}
fun fetchAuth(tvModel: TVViewModel) {
if (token == "") {
yspTokenService.getInfo()
.enqueue(object : Callback<Info> {
override fun onResponse(call: Call<Info>, response: Response<Info>) {
if (response.isSuccessful) {
token = response.body()?.data?.token!!
Log.i(TAG, "info success $token")
val cookie =
"versionName=99.99.99; versionCode=999999; vplatform=109; platformVersion=Chrome; deviceModel=120; appid=1400421205; yspappid=519748109;yspopenid=vu0-8lgGV2LW9QjDeuBFsX8yMnzs37Q3_HZF6XyVDpGR_I; vusession=$token"
fetchAuth(tvModel, cookie)
} else {
Log.e(TAG, "info status error")
if (tvModel.tokenRetryTimes < tvModel.tokenRetryMaxTimes) {
tvModel.tokenRetryTimes++
fetchAuth(tvModel)
} else {
if (!tvModel.getTV().mustToken) {
val cookie =
"versionName=99.99.99; versionCode=999999; vplatform=109; platformVersion=Chrome; deviceModel=120; appid=1400421205; yspappid=519748109"
fetchAuth(tvModel, cookie)
}
}
}
}
override fun onFailure(call: Call<Info>, t: Throwable) {
Log.e(TAG, "info request error $t")
if (tvModel.tokenRetryTimes < tvModel.tokenRetryMaxTimes) {
tvModel.tokenRetryTimes++
fetchVideo(tvModel)
} else {
if (!tvModel.getTV().mustToken) {
val cookie =
"versionName=99.99.99; versionCode=999999; vplatform=109; platformVersion=Chrome; deviceModel=120; appid=1400421205; yspappid=519748109"
fetchAuth(tvModel, cookie)
}
}
}
})
} else {
val cookie =
"versionName=99.99.99; versionCode=999999; vplatform=109; platformVersion=Chrome; deviceModel=120; appid=1400421205; yspappid=519748109;yspopenid=vu0-8lgGV2LW9QjDeuBFsX8yMnzs37Q3_HZF6XyVDpGR_I; vusession=$token"
fetchAuth(tvModel, cookie)
}
}
fun fetchVideo(tvModel: TVViewModel) {
if (token == "") {
yspTokenService.getInfo()
@ -184,7 +311,7 @@ class Request {
token = response.body()?.data?.token!!
Log.i(TAG, "info success $token")
val cookie =
"versionName=99.99.99; versionCode=999999; vplatform=109; platformVersion=Chrome; deviceModel=120; yspappid=519748109;yspopenid=vu0-8lgGV2LW9QjDeuBFsX8yMnzs37Q3_HZF6XyVDpGR_I; vusession=$token"
"versionName=99.99.99; versionCode=999999; vplatform=109; platformVersion=Chrome; deviceModel=120; appid=1400421205; yspappid=519748109;yspopenid=vu0-8lgGV2LW9QjDeuBFsX8yMnzs37Q3_HZF6XyVDpGR_I; vusession=$token"
fetchVideo(tvModel, cookie)
} else {
Log.e(TAG, "info status error")
@ -194,7 +321,7 @@ class Request {
} else {
if (!tvModel.getTV().mustToken) {
val cookie =
"versionName=99.99.99; versionCode=999999; vplatform=109; platformVersion=Chrome; deviceModel=120; yspappid=519748109"
"versionName=99.99.99; versionCode=999999; vplatform=109; platformVersion=Chrome; deviceModel=120; appid=1400421205; yspappid=519748109"
fetchVideo(tvModel, cookie)
}
}
@ -209,7 +336,7 @@ class Request {
} else {
if (!tvModel.getTV().mustToken) {
val cookie =
"versionName=99.99.99; versionCode=999999; vplatform=109; platformVersion=Chrome; deviceModel=120; yspappid=519748109"
"versionName=99.99.99; versionCode=999999; vplatform=109; platformVersion=Chrome; deviceModel=120; appid=1400421205; yspappid=519748109"
fetchVideo(tvModel, cookie)
}
}
@ -217,18 +344,20 @@ class Request {
})
} else {
val cookie =
"versionName=99.99.99; versionCode=999999; vplatform=109; platformVersion=Chrome; deviceModel=120; yspappid=519748109;yspopenid=vu0-8lgGV2LW9QjDeuBFsX8yMnzs37Q3_HZF6XyVDpGR_I; vusession=$token"
"versionName=99.99.99; versionCode=999999; vplatform=109; platformVersion=Chrome; deviceModel=120; appid=1400421205; yspappid=519748109;yspopenid=vu0-8lgGV2LW9QjDeuBFsX8yMnzs37Q3_HZF6XyVDpGR_I; vusession=$token"
fetchVideo(tvModel, cookie)
}
}
fun fetchData(tvModel: TVViewModel) {
if (tvModel.getTV().needToken) {
fetchVideo(tvModel)
// fetchVideo(tvModel)
fetchAuth(tvModel)
} else {
val cookie =
"versionName=99.99.99; versionCode=999999; vplatform=109; platformVersion=Chrome; deviceModel=120; yspappid=519748109"
fetchVideo(tvModel, cookie)
"versionName=99.99.99; versionCode=999999; vplatform=109; platformVersion=Chrome; deviceModel=120; appid=1400421205"
// fetchVideo(tvModel, cookie)
fetchAuth(tvModel, cookie)
}
}

@ -6,9 +6,12 @@ import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.database.Cursor
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.os.Handler
import android.os.Looper
import android.util.Log
import android.widget.Toast
import com.lizongying.mytv.api.Release
@ -66,6 +69,7 @@ class UpdateManager(
val downloadManager =
context!!.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
val request = Request(Uri.parse(release.data.downloadUrl))
Log.i(TAG, "url ${Uri.parse(release.data.downloadUrl)}")
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, apkFileName)
request.setTitle("New Version Download")
request.setNotificationVisibility(Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
@ -87,6 +91,48 @@ class UpdateManager(
IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE)
)
}
getDownloadProgress(context!!, downloadReference) { progress ->
println("Download progress: $progress%")
}
}
private fun getDownloadProgress(context: Context, downloadId: Long, progressListener: (Int) -> Unit) {
val downloadManager = context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
val handler = Handler(Looper.getMainLooper())
val intervalMillis: Long = 1000
handler.post(object : Runnable {
override fun run() {
Log.i(TAG, "search")
val query = DownloadManager.Query().setFilterById(downloadId)
val cursor: Cursor = downloadManager.query(query)
cursor.use {
if (it.moveToFirst()) {
val bytesDownloadedIndex =
it.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR)
val bytesTotalIndex =
it.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES)
// 检查列名是否存在
if (bytesDownloadedIndex != -1 && bytesTotalIndex != -1) {
val bytesDownloaded = it.getInt(bytesDownloadedIndex)
val bytesTotal = it.getInt(bytesTotalIndex)
if (bytesTotal != -1) {
val progress = (bytesDownloaded * 100L / bytesTotal).toInt()
progressListener(progress)
if (progress == 100) {
return
}
}
}
}
}
// handler.postDelayed(this, intervalMillis)
}
})
}
private class DownloadReceiver(

@ -5,6 +5,8 @@ import okhttp3.OkHttpClient
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

@ -0,0 +1,37 @@
package com.lizongying.mytv.api
import android.util.Log
import okhttp3.MediaType
import okhttp3.RequestBody
import okio.BufferedSink
import java.io.IOException
data class Auth(
val code: Int,
val msg: String,
val data: AuthData,
)
data class AuthData(
val token: String,
)
data class AuthRequest(
var data: String,
) : RequestBody() {
override fun contentType(): MediaType? {
return MediaType.parse("application/x-www-form-urlencoded;charset=UTF-8")
}
override fun writeTo(sink: BufferedSink) {
try {
sink.writeUtf8(data)
} catch (e: IOException) {
Log.e(TAG, "$e")
}
}
companion object {
private const val TAG = "AuthRequest"
}
}

@ -50,6 +50,9 @@ class YSP(var context: Context) {
private var signature = ""
private var appid = "ysp_pc"
var token = ""
private var encryptor: Encryptor? = null
private lateinit var sharedPref: SharedPreferences
@ -83,6 +86,19 @@ class YSP(var context: Context) {
return """{"cnlid":"$cnlid","livepid":"$livepid","stream":"$stream","guid":"$guid","cKey":"$cKey","adjust":$adjust,"sphttps":"$sphttps","platform":"$platform","cmd":"$cmd","encryptVer":"$encryptVer","dtype":"$dtype","devid":"$devid","otype":"$otype","appVer":"$appVer","app_version":"$appVersion","rand_str":"$randStr","channel":"$channel","defn":"$defn","signature":"$signature"}"""
}
fun getAuthData(tvModel: TVViewModel): String {
livepid = tvModel.pid.value!!
randStr = getRand()
if (tvModel.retryTimes > 0) {
guid = newGuid()
}
signature = getAuthSignature()
return """pid=$livepid&guid=$guid&appid=$appid&rand_str=$randStr&signature=$signature"""
}
private fun getTimeStr(): String {
return getDateTimestamp().toString()
}
@ -131,6 +147,13 @@ class YSP(var context: Context) {
return hashedData.let { it -> it.joinToString("") { "%02x".format(it) } }
}
private fun getAuthSignature(): String {
val e =
"appid=${appid}&guid=${guid}&pid=${livepid}&rand_str=${randStr}".toByteArray()
val hashedData = encryptor?.hash2(e) ?: return ""
return hashedData.let { it -> it.joinToString("") { "%02x".format(it) } }
}
companion object {
private const val TAG = "YSP"
}

@ -13,9 +13,23 @@ interface YSPApiService {
"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 getLiveInfo(
@Header("cookie") cookie: String,
@Header("Yspplayertoken") token: String,
@Body request: LiveInfoRequest,
): Call<LiveInfo>
@POST("v1/player/auth")
@Headers(
"content-type: application/x-www-form-urlencoded;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 getAuth(
@Header("cookie") cookie: String,
@Body request: AuthRequest,
): Call<Auth>
}
Loading…
Cancel
Save