diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 71beb31..d037f54 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -37,6 +37,13 @@ jobs: # override default build-tools version (29.0.3) -- optional BUILD_TOOLS_VERSION: "34.0.0" + - name: Get History + id: get_history + run: | + chmod +x history.sh + output=$(./history.sh) + echo "$output" > history.md + - name: Create Release id: create_release uses: actions/create-release@v1 @@ -47,6 +54,7 @@ jobs: release_name: Release ${{ github.ref }} draft: false prerelease: false + body_path: history.md - name: Upload Release Asset uses: actions/upload-release-asset@v1 @@ -56,4 +64,19 @@ jobs: upload_url: ${{ steps.create_release.outputs.upload_url }} asset_path: ${{ steps.sign_app.outputs.signedReleaseFile }} asset_name: my-tv-${{ github.ref_name }}.apk - asset_content_type: application/vnd.android.package-archive \ No newline at end of file + asset_content_type: application/vnd.android.package-archive + + - name: Gitee Create Release + run: | + latest_commit=$(git rev-parse HEAD) + history=$(cat history.md) + curl -v POST https://gitee.com/api/v5/repos/${{ github.repository }}/releases \ + -H "Content-Type: application/json" \ + -d '{ + "access_token": "${{ secrets.GITEE_ACCESS_TOKEN}}", + "tag_name": "${{ github.ref_name }}", + "name": "Release ${{ github.ref_name }}", + "body": "'"$history"'", + "prerelease": false, + "target_commitish": "'"$latest_commit"'" + }' \ No newline at end of file diff --git a/HISTORY.md b/HISTORY.md index 8350a29..9ef9c22 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,9 @@ ## 更新日志 +### v2.0.2 + +* 修复不能播放的问题 + ### v2.0.0 * 解决卡顿问题 diff --git a/app/src/main/cpp/arm64-v8a/libnative.so b/app/src/main/cpp/arm64-v8a/libnative.so index 67fed52..001109a 100755 Binary files a/app/src/main/cpp/arm64-v8a/libnative.so and b/app/src/main/cpp/arm64-v8a/libnative.so differ diff --git a/app/src/main/cpp/armeabi-v7a/libnative.so b/app/src/main/cpp/armeabi-v7a/libnative.so index 43a8ca0..202af30 100755 Binary files a/app/src/main/cpp/armeabi-v7a/libnative.so and b/app/src/main/cpp/armeabi-v7a/libnative.so differ diff --git a/app/src/main/java/com/lizongying/mytv/MainFragment.kt b/app/src/main/java/com/lizongying/mytv/MainFragment.kt index d9f1cc1..f9835e0 100644 --- a/app/src/main/java/com/lizongying/mytv/MainFragment.kt +++ b/app/src/main/java/com/lizongying/mytv/MainFragment.kt @@ -50,7 +50,7 @@ class MainFragment : Fragment(), CardAdapter.ItemListener { inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View { - var context = requireContext() + val context = requireContext() _binding = MenuBinding.inflate(inflater, container, false) application = requireActivity().applicationContext as MyTvApplication 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 19a52c0..aab455f 100644 --- a/app/src/main/java/com/lizongying/mytv/api/ApiClient.kt +++ b/app/src/main/java/com/lizongying/mytv/api/ApiClient.kt @@ -24,6 +24,7 @@ class ApiClient { private val protoUrl = "https://capi.yangshipin.cn/" private val traceUrl = "https://btrace.yangshipin.cn/" private val trace2Url = "https://aatc-api.yangshipin.cn/" + private val tokenUrl = "https://h5access.yangshipin.cn/" private val trace3Url = "https://dtrace.ysp.cctv.cn/" private val jceUrl = "https://jacc.ysp.cctv.cn/" private val fUrl = "https://m.fengshows.com/" @@ -78,6 +79,14 @@ class ApiClient { .build().create(YSPBtraceService::class.java) } + val yspToken2Service: YSPApiService by lazy { + Retrofit.Builder() + .baseUrl(tokenUrl) + .client(okHttpClient) + .addConverterFactory(GsonConverterFactory.create()) + .build().create(YSPApiService::class.java) + } + val yspBtraceService3: YSPBtraceService by lazy { Retrofit.Builder() .baseUrl(trace3Url) @@ -157,7 +166,7 @@ class ApiClient { val sslContext = SSLContext.getInstance("SSL") sslContext.init(null, trustAllCerts, java.security.SecureRandom()) - val proxy = Proxy(Proxy.Type.HTTP, InetSocketAddress("10.0.2.2", 8888)) +// val proxy = Proxy(Proxy.Type.HTTP, InetSocketAddress("10.0.2.2", 8888)) val builder = OkHttpClient.Builder() .sslSocketFactory(sslContext.socketFactory, trustAllCerts[0] as X509TrustManager) diff --git a/app/src/main/java/com/lizongying/mytv/api/Token2.kt b/app/src/main/java/com/lizongying/mytv/api/Token2.kt new file mode 100644 index 0000000..2f109f6 --- /dev/null +++ b/app/src/main/java/com/lizongying/mytv/api/Token2.kt @@ -0,0 +1,11 @@ +package com.lizongying.mytv.api + +data class Token2( + val ret: Int?, + val msg: String?, + val data: Data, +) { + data class Data( + val token: String, + ) +} 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 b2e7f5c..7137486 100644 --- a/app/src/main/java/com/lizongying/mytv/api/YSP.kt +++ b/app/src/main/java/com/lizongying/mytv/api/YSP.kt @@ -1,9 +1,11 @@ package com.lizongying.mytv.api import android.content.Context +import android.util.Log import com.lizongying.mytv.SP import com.lizongying.mytv.Utils.getDateTimestamp import com.lizongying.mytv.models.TVViewModel +import java.security.MessageDigest import kotlin.math.floor import kotlin.random.Random @@ -52,6 +54,13 @@ object YSP { private var appid = "ysp_pc" var token = "" + var token2 = "" + + var yspsdkinput = "" + var openapi_signature = "" + + var nseqId = 1 + var nrequest_id = "" private var encryptor = Encryptor() @@ -75,10 +84,43 @@ object YSP { cKey = encryptor.encrypt(cnlid, timeStr, appVer, guid, platform) + randStr = getRand() signature = getSignature() 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 getTokenData(tvModel: TVViewModel) { + livepid = tvModel.getTV().pid + cnlid = tvModel.getTV().sid + defn = "fhd" + + randStr = getRand() + + if (tvModel.retryTimes > 0) { + guid = newGuid() + } + + cKey = + encryptor.encrypt(cnlid, timeStr, appVer, guid, platform) + + Log.i(TAG,"yspsdkinput ${"""{"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","channel":"$channel","defn":"$defn"}"""}" ) + + yspsdkinput = md("adjust=$adjust&app_version=$appVersion&appVer=$appVer&channel=$channel&cKey=$cKey&cmd=$cmd&cnlid=$cnlid&defn=$defn&devid=$devid&dtype=$dtype&encryptVer=$encryptVer&guid=$guid&livepid=$livepid&otype=$otype&platform=$platform&sphttps=$sphttps&stream=$stream") + + nseqId++ + + nrequest_id = "999999" + getRand() + getTimeStr() + + openapi_signature = md("yspappid:519748109;host:www.yangshipin.cn;protocol:https:;token:$token2;input:$yspsdkinput-$guid-$nseqId-$nrequest_id;") + } + + fun md(str:String):String { + val md = MessageDigest.getInstance("MD5") + md.update(str.toByteArray()) + val digest = md.digest() + return digest.let { it -> it.joinToString("") { "%02x".format(it) } } + } + fun getAuthData(tvModel: TVViewModel): String { livepid = tvModel.getTV().pid @@ -92,7 +134,7 @@ object YSP { return """pid=$livepid&guid=$guid&appid=$appid&rand_str=$randStr&signature=$signature""" } - private fun getTimeStr(): String { + fun getTimeStr(): String { return getDateTimestamp().toString() } 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..6adbb3d 100644 --- a/app/src/main/java/com/lizongying/mytv/api/YSPApiService.kt +++ b/app/src/main/java/com/lizongying/mytv/api/YSPApiService.kt @@ -2,9 +2,11 @@ package com.lizongying.mytv.api import retrofit2.Call import retrofit2.http.Body +import retrofit2.http.GET import retrofit2.http.Header import retrofit2.http.Headers import retrofit2.http.POST +import retrofit2.http.Query interface YSPApiService { @@ -18,6 +20,11 @@ interface YSPApiService { fun getLiveInfo( @Header("cookie") cookie: String, @Header("Yspplayertoken") token: String, + @Header("Yspsdkinput") Yspsdkinput: String, + @Header("yspsdksign") yspsdksign: String, + @Header("Seqid") Seqid: String, + @Header("Request-Id") RequestId: String, + @Header("Yspappid") Yspappid: String="519748109", @Body request: LiveInfoRequest, ): Call @@ -32,4 +39,20 @@ interface YSPApiService { @Header("cookie") cookie: String, @Body request: AuthRequest, ): Call + + @GET("web/open/token") + @Headers( + "content-type: application/json", + "referer: https://www.yangshipin.cn/", + "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 getToken( + @Header("cookie") cookie: String, + @Query("yspappid") yspappid: String = "519748109", + @Query("guid") guid: String = "", + @Query("vappid") vappid: String = "59306155", + @Query("vsecret") vsecret: String = "b42702bf7309a179d102f3d51b1add2fda0bc7ada64cb801", + @Query("raw") raw: String = "1", + @Query("ts") ts: String = "", + ): Call } \ No newline at end of file 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 d20082e..180e948 100644 --- a/app/src/main/java/com/lizongying/mytv/models/TVViewModel.kt +++ b/app/src/main/java/com/lizongying/mytv/models/TVViewModel.kt @@ -15,7 +15,7 @@ class TVViewModel(private var tv: TV) : ViewModel() { private var itemPosition: Int = 0 var retryTimes = 0 - var retryMaxTimes = 8 + var retryMaxTimes = 1 var authYSPRetryTimes = 0 var authYSPRetryMaxTimes = 3 var tokenYSPRetryTimes = 0 diff --git a/app/src/main/java/com/lizongying/mytv/requests/Request.kt b/app/src/main/java/com/lizongying/mytv/requests/Request.kt index 554a604..8d6d092 100644 --- a/app/src/main/java/com/lizongying/mytv/requests/Request.kt +++ b/app/src/main/java/com/lizongying/mytv/requests/Request.kt @@ -18,6 +18,7 @@ import com.lizongying.mytv.api.KvcollectRequest import com.lizongying.mytv.api.KvcollectRequest2 import com.lizongying.mytv.api.LiveInfo import com.lizongying.mytv.api.LiveInfoRequest +import com.lizongying.mytv.api.Token2 import com.lizongying.mytv.api.YSP import com.lizongying.mytv.api.YSPApiService import com.lizongying.mytv.api.YSPBtraceService @@ -42,6 +43,7 @@ import kotlin.random.Random object Request { private const val TAG = "Request" private var yspTokenService: YSPTokenService = ApiClient().yspTokenService + private var yspToken2Service: YSPApiService = ApiClient().yspToken2Service private var yspApiService: YSPApiService = ApiClient().yspApiService private var yspBtraceService: YSPBtraceService = ApiClient().yspBtraceService private var yspBtraceService2: YSPBtraceService = ApiClient().yspBtraceService2 @@ -56,6 +58,7 @@ object Request { private var needAuth = true private var needToken = false + private var needToken2 = true private val handler = Handler(Looper.getMainLooper()) private lateinit var btraceRunnable: BtraceRunnable @@ -74,6 +77,7 @@ object Request { } private var call: Call? = null + private var callToken: Call? = null private var callAuth: Call? = null private var callInfo: Call? = null private var callFAuth: Call? = null @@ -84,11 +88,117 @@ object Request { private fun cancelCall() { call?.cancel() callAuth?.cancel() + callToken?.cancel() callInfo?.cancel() callFAuth?.cancel() callPage?.cancel() } + + private fun fetchToken(tvModel: TVViewModel, cookie: String) { + cancelCall() + + val title = tvModel.getTV().title + + callToken = yspToken2Service.getToken("guid=${YSP.getGuid()}; $cookie", "519748109", YSP.getGuid(), "59306155", "b42702bf7309a179d102f3d51b1add2fda0bc7ada64cb801" ,"1", YSP.getTimeStr()) + callToken?.enqueue(object : Callback { + override fun onResponse(call: Call, response: Response) { + if (response.isSuccessful) { + val liveInfo = response.body() + + if (liveInfo?.data?.token != null) { + Log.i(TAG, "token ${liveInfo.data.token}") + YSP.token2 = liveInfo.data.token + + YSP.getTokenData(tvModel) + + fetchAuth(tvModel, cookie) + } else { + Log.e(TAG, "$title token error") + if (tvModel.retryTimes < tvModel.retryMaxTimes) { + tvModel.retryTimes++ + if (tvModel.getTV().needToken) { + if (needToken && tvModel.tokenYSPRetryTimes < tvModel.tokenYSPRetryMaxTimes) { + tvModel.tokenYSPRetryTimes++ + tvModel.needGetToken = true + fetchToken(tvModel) + } else { + if (!tvModel.getTV().mustToken) { + fetchToken(tvModel, cookie) + } else { + val err = "错误" + Log.e(TAG, "$title $err") + tvModel.setErrInfo(err) + } + } + } else { + fetchToken(tvModel, cookie) + } + } else { + val err = "认证结果错误" + Log.e(TAG, "$title $err") + tvModel.setErrInfo(err) + } + } + } else { + Log.e(TAG, "$title token status error") + if (tvModel.retryTimes < tvModel.retryMaxTimes) { + tvModel.retryTimes++ + if (tvModel.getTV().needToken) { + if (needToken && tvModel.tokenYSPRetryTimes < tvModel.tokenYSPRetryMaxTimes) { + tvModel.tokenYSPRetryTimes++ + tvModel.needGetToken = true + fetchToken(tvModel) + } else { + if (!tvModel.getTV().mustToken) { + fetchToken(tvModel, cookie) + } else { + val err = "错误" + Log.e(TAG, "$title $err") + tvModel.setErrInfo(err) + } + } + } else { + fetchToken(tvModel, cookie) + } + } else { + val err = "认证状态错误" + Log.e(TAG, "$title $err") + tvModel.setErrInfo(err) + } + } + } + + override fun onFailure(call: Call, t: Throwable) { + Log.e(TAG, "$title token request error $t") + if (tvModel.retryTimes < tvModel.retryMaxTimes) { + tvModel.retryTimes++ + if (tvModel.getTV().needToken) { + if (needToken && tvModel.tokenYSPRetryTimes < tvModel.tokenYSPRetryMaxTimes) { + tvModel.tokenYSPRetryTimes++ + tvModel.needGetToken = true + fetchToken(tvModel) + } else { + if (!tvModel.getTV().mustToken) { + fetchToken(tvModel, cookie) + } else { + val err = "错误" + Log.e(TAG, "$title $err") + tvModel.setErrInfo(err) + } + } + } else { + fetchToken(tvModel, cookie) + } + } else { + val err = "认证请求错误" + Log.e(TAG, "$title $err") + tvModel.setErrInfo(err) + } + } + }) + } + private fun fetchAuth(tvModel: TVViewModel, cookie: String) { cancelCall() @@ -103,11 +213,11 @@ object Request { val liveInfo = response.body() if (liveInfo?.data?.token != null) { - Log.i(TAG, "token ${liveInfo.data.token}") + Log.i(TAG, "auth ${liveInfo.data.token}") YSP.token = liveInfo.data.token fetchVideo(tvModel, cookie) } else { - Log.e(TAG, "$title token error") + Log.e(TAG, "$title auth error") if (tvModel.retryTimes < tvModel.retryMaxTimes) { tvModel.retryTimes++ if (tvModel.getTV().needToken) { @@ -206,8 +316,13 @@ object Request { val request = LiveInfoRequest(data) call = request.let { yspApiService.getLiveInfo( - "guid=${YSP.getGuid()}; $cookie", + "guid=${YSP.getGuid()}; gr_user_id=261eecf2-0ce4-4316-a6a1-7171e3de7389; $cookie; newLogin=1; nseqId=${YSP.nseqId}; nrequest-id=${YSP.nrequest_id}", YSP.token, + YSP.yspsdkinput, + YSP.openapi_signature, + "${YSP.nseqId}", + YSP.nrequest_id, + "519748109", it ) } @@ -392,6 +507,66 @@ object Request { }) } + private fun fetchToken(tvModel: TVViewModel) { + cancelCall() + if (tvModel.needGetToken) { + callInfo = yspTokenService.getInfo("") + callInfo?.enqueue(object : Callback { + override fun onResponse(call: Call, response: Response) { + if (response.isSuccessful && response.body()?.data?.token != null) { + token = response.body()?.data?.token!! + Log.i(TAG, "info success $token") + tvModel.needGetToken = false + tvModel.tokenYSPRetryTimes = 0 + val cookie = + "versionName=99.99.99; versionCode=999999; vplatform=109; platformVersion=Chrome; deviceModel=124; appid=1400421205; yspappid=519748109;yspopenid=$openid; vusession=$token" + fetchAuth(tvModel, cookie) + } else if (response.code() == 304) { + tvModel.needGetToken = false + tvModel.tokenYSPRetryTimes = 0 + val cookie = + "versionName=99.99.99; versionCode=999999; vplatform=109; platformVersion=Chrome; deviceModel=124; appid=1400421205; yspappid=519748109; yspopenid=$openid; vusession=$token" + fetchVideo(tvModel, cookie) + } else { + Log.e(TAG, "info status error") + if (tvModel.tokenYSPRetryTimes < tvModel.tokenYSPRetryMaxTimes) { + tvModel.tokenYSPRetryTimes++ + fetchToken(tvModel) + } else { + if (!tvModel.getTV().mustToken) { + val cookie = + "versionName=99.99.99; versionCode=999999; vplatform=109; platformVersion=Chrome; deviceModel=124; appid=1400421205; yspappid=519748109" + fetchToken(tvModel, cookie) + } else { +// TODO + } + } + } + } + + override fun onFailure(call: Call, t: Throwable) { + Log.e(TAG, "info request error $t") + if (tvModel.tokenYSPRetryTimes < tvModel.tokenYSPRetryMaxTimes) { + tvModel.tokenYSPRetryTimes++ + fetchAuth(tvModel) + } else { + if (!tvModel.getTV().mustToken) { + val cookie = + "versionName=99.99.99; versionCode=999999; vplatform=109; platformVersion=Chrome; deviceModel=124; appid=1400421205; yspappid=519748109" + fetchToken(tvModel, cookie) + } else { +// TODO + } + } + } + }) + } else { + val cookie = + "versionName=99.99.99; versionCode=999999; vplatform=109; platformVersion=Chrome; deviceModel=124; appid=1400421205; yspappid=519748109;yspopenid=$openid; vusession=$token" + fetchToken(tvModel, cookie) + } + } + private fun fetchAuth(tvModel: TVViewModel) { cancelCall() if (tvModel.needGetToken) { @@ -447,7 +622,7 @@ object Request { }) } else { val cookie = - "versionName=99.99.99; versionCode=999999; vplatform=109; platformVersion=Chrome; deviceModel=120; appid=1400421205; yspappid=519748109;yspopenid=$openid; vusession=$token" + "versionName=99.99.99; versionCode=999999; vplatform=109; platformVersion=Chrome; deviceModel=124; yspopenid=$openid; vusession=$token" fetchAuth(tvModel, cookie) } } @@ -569,19 +744,42 @@ object Request { if (token == "") { tvModel.needGetToken = true } - if (needAuth) { - fetchAuth(tvModel) + if (needToken2) { + if (needAuth) { + fetchToken(tvModel) + } else { + fetchAuth(tvModel) + } } else { - fetchVideo(tvModel) + if (needAuth) { + fetchAuth(tvModel) + } else { + fetchVideo(tvModel) + } } } else { val cookie = - "versionName=99.99.99; versionCode=999999; vplatform=109; platformVersion=Chrome; updateProtocol=1; deviceModel=120" - if (needAuth) { - fetchAuth(tvModel, cookie) + "versionName=99.99.99; versionCode=999999; vplatform=109; platformVersion=Chrome; deviceModel=124" + + if (needToken2) { + if (needAuth) { + fetchToken(tvModel, cookie) + } else { + fetchAuth(tvModel, cookie) + } } else { - fetchVideo(tvModel, cookie) + if (needAuth) { + fetchAuth(tvModel, cookie) + } else { + fetchVideo(tvModel, cookie) + } } +// +// if (needAuth) { +// fetchAuth(tvModel, cookie) +// } else { +// fetchVideo(tvModel, cookie) +// } } } diff --git a/version.json b/version.json index bce610d..188acfe 100644 --- a/version.json +++ b/version.json @@ -1 +1 @@ -{"version_code": 33554432, "version_name": "v2.0.0"} +{"version_code": 33554944, "version_name": "v2.0.2"}