mirror of
https://github.com/lizongying/my-tv.git
synced 2026-10-27 14:46:30 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
52c7887951 |
@@ -22,7 +22,7 @@ jobs:
|
||||
distribution: 'temurin'
|
||||
|
||||
- name: Run build with Gradle wrapper
|
||||
run: ./gradlew assembleRelease -PIS_SO_BUILD=false
|
||||
run: ./gradlew assembleRelease
|
||||
|
||||
- name: Sign app APK
|
||||
id: sign_app
|
||||
|
||||
+1
-1
@@ -3,4 +3,4 @@
|
||||
/cmake_install.cmake
|
||||
/CMakeFiles/
|
||||
/Makefile
|
||||
/src/main/cpp/native.c
|
||||
/src/main/cpp/native-lib.c
|
||||
|
||||
+2
-1
@@ -24,7 +24,8 @@ android {
|
||||
|
||||
// For ndk-build, instead use the ndkBuild block.
|
||||
cmake {
|
||||
arguments "-DIS_SO_BUILD=${project.hasProperty('IS_SO_BUILD') ? project.IS_SO_BUILD : true}"
|
||||
// arguments "-DIS_SO_BUILD=${project.hasProperty('IS_SO_BUILD') ? project.IS_SO_BUILD : false}"
|
||||
arguments "-DIS_SO_BUILD=${false}"
|
||||
|
||||
abiFilters "armeabi-v7a", "arm64-v8a"
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,327 @@
|
||||
#include "stdio.h"
|
||||
#include "jni.h"
|
||||
#include <openssl/rand.h>
|
||||
#include <string.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/md5.h>
|
||||
#include <android/log.h>
|
||||
#include <stdbool.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#define APP_SIGNATURE "f0005d8a185c47e72946053a0af5c0f5620605dd9e301ef0937e477f607ab0d7"
|
||||
#define APP_SIGNATURE2 "9e58fc98c3967ae80eb25541241895368a900fa488e015b08614575c18fab95e"
|
||||
|
||||
#define TAG "native"
|
||||
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
|
||||
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)
|
||||
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, TAG, __VA_ARGS__)
|
||||
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
|
||||
|
||||
static bool signatureVerified = false;
|
||||
|
||||
static const char key[33] = "48e5918a74ae21c972b90cce8af6c8be";
|
||||
static const char iv[33] = "9a7e7d23610266b1d9fbf98581384d92";
|
||||
static const char appendString[15] = "0f$IVHi9Qno?G";
|
||||
|
||||
static void toUpperCase(char *str) {
|
||||
while (*str) {
|
||||
*str = toupper((unsigned char) *str);
|
||||
str++;
|
||||
}
|
||||
}
|
||||
|
||||
static char *binaryToHex(const unsigned char *data, size_t dataSize) {
|
||||
char *hexString = (char *) malloc(dataSize * 2 + 1); // 每个字节需要两个十六进制字符,再加上字符串结束符
|
||||
if (hexString == NULL) {
|
||||
// 内存分配失败
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < dataSize; ++i) {
|
||||
sprintf(hexString + i * 2, "%02X", data[i]);
|
||||
}
|
||||
|
||||
hexString[dataSize * 2] = '\0'; // 添加字符串结束符
|
||||
|
||||
return hexString;
|
||||
}
|
||||
|
||||
static unsigned char *hexStringToBinary(const char *hexString1) {
|
||||
size_t inputLength = strlen(hexString1);
|
||||
if (inputLength % 2 != 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t length = inputLength / 2;
|
||||
unsigned char *result1 = (unsigned char *) malloc(length);
|
||||
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
char byteString[3] = {hexString1[2 * i], hexString1[2 * i + 1], '\0'};
|
||||
result1[i] = (unsigned char) strtoul(byteString, NULL, 16);
|
||||
}
|
||||
|
||||
return result1;
|
||||
}
|
||||
|
||||
static char *aes(const char *plaintext) {
|
||||
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
|
||||
if (ctx == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// const char k[33] = "48e5918a74ae21c972b90cce8af6c8be";
|
||||
unsigned char *resultKey = hexStringToBinary(key);
|
||||
|
||||
// const char i[33] = "9a7e7d23610266b1d9fbf98581384d92";
|
||||
unsigned char *resultIv = hexStringToBinary(iv);
|
||||
|
||||
if (EVP_EncryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, resultKey, resultIv) != 1) {
|
||||
free(resultKey);
|
||||
free(resultIv);
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EVP_CIPHER_CTX_set_padding(ctx, 1);
|
||||
|
||||
size_t dataLength = strlen(plaintext);
|
||||
|
||||
size_t maxEncryptedLength = dataLength + EVP_CIPHER_block_size(EVP_aes_128_cbc());
|
||||
unsigned char *encryptedData = (unsigned char *) malloc(maxEncryptedLength);
|
||||
if (encryptedData == NULL) {
|
||||
free(resultKey);
|
||||
free(resultIv);
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int len;
|
||||
if (EVP_EncryptUpdate(ctx, encryptedData, &len, (const unsigned char *) plaintext,
|
||||
(int) dataLength) !=
|
||||
1) {
|
||||
free(resultKey);
|
||||
free(resultIv);
|
||||
free(encryptedData);
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t encryptedLength = len;
|
||||
|
||||
if (EVP_EncryptFinal_ex(ctx, encryptedData + len, &len) != 1) {
|
||||
free(resultKey);
|
||||
free(resultIv);
|
||||
free(encryptedData);
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 更新加密数据长度
|
||||
encryptedLength += len;
|
||||
|
||||
// 创建一个 C 字符串以容纳加密后的数据
|
||||
char *encryptedString = binaryToHex(encryptedData, encryptedLength);
|
||||
if (encryptedString == NULL) {
|
||||
// 内存分配失败
|
||||
free(resultKey);
|
||||
free(resultIv);
|
||||
free(encryptedData);
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 释放内存和资源
|
||||
free(resultKey);
|
||||
free(resultIv);
|
||||
free(encryptedData);
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
|
||||
return encryptedString;
|
||||
}
|
||||
|
||||
jbyte *appendStringToEnd(jbyte *data, size_t *dataLength) {
|
||||
// 获取原始数据长度
|
||||
size_t originalLength = *dataLength;
|
||||
|
||||
size_t appendStringLength = strlen(appendString);
|
||||
|
||||
// 分配新的内存空间,包括原始数据和附加字符串
|
||||
data = (jbyte *) realloc(data,
|
||||
originalLength + appendStringLength + 1);
|
||||
|
||||
if (data == NULL) {
|
||||
// 内存分配失败的处理
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 将附加字符串复制到新的内存空间的末尾
|
||||
memcpy(data + originalLength, appendString, appendStringLength);
|
||||
|
||||
// 在新数据的末尾添加 null 终止字符
|
||||
data[originalLength + appendStringLength] = '\0';
|
||||
|
||||
// 更新数据长度
|
||||
*dataLength = originalLength + appendStringLength + 1;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
JNIEXPORT jbyteArray
|
||||
|
||||
JNICALL
|
||||
Java_com_lizongying_mytv_Encryptor_hash(JNIEnv *env, jobject thiz, jbyteArray data_) {
|
||||
if (signatureVerified == false) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
jbyte *data = (*env)->GetByteArrayElements(env, data_, NULL);
|
||||
|
||||
// 获取数据长度
|
||||
size_t dataLength = (*env)->GetArrayLength(env, data_);
|
||||
|
||||
// LOGI("appendStringLength %s", data);
|
||||
data = appendStringToEnd(data, &dataLength);
|
||||
|
||||
dataLength = strlen((const char *) data);
|
||||
// LOGI("dataLength %d", dataLength);
|
||||
|
||||
// 分配内存以存储 MD5 值(16 字节)
|
||||
unsigned char md5Digest[EVP_MAX_MD_SIZE];
|
||||
unsigned int md5DigestLength;
|
||||
|
||||
// 创建 MD5 上下文
|
||||
EVP_MD_CTX *md5Context = EVP_MD_CTX_new();
|
||||
if (md5Context == NULL) {
|
||||
// 处理错误
|
||||
(*env)->ReleaseByteArrayElements(env, data_, data, 0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 初始化 MD5 上下文
|
||||
if (EVP_DigestInit_ex(md5Context, EVP_md5(), NULL) != 1) {
|
||||
// 处理错误
|
||||
EVP_MD_CTX_free(md5Context);
|
||||
(*env)->ReleaseByteArrayElements(env, data_, data, 0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 更新 MD5 上下文
|
||||
if (EVP_DigestUpdate(md5Context, data, dataLength) != 1) {
|
||||
// 处理错误
|
||||
EVP_MD_CTX_free(md5Context);
|
||||
(*env)->ReleaseByteArrayElements(env, data_, data, 0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 获取 MD5 值
|
||||
if (EVP_DigestFinal_ex(md5Context, md5Digest, &md5DigestLength) != 1) {
|
||||
// 处理错误
|
||||
EVP_MD_CTX_free(md5Context);
|
||||
(*env)->ReleaseByteArrayElements(env, data_, data, 0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
jsize md5Length = (jsize) md5DigestLength;
|
||||
|
||||
// 创建 Java 字节数组以容纳 MD5 值
|
||||
jbyteArray md5Array = (*env)->NewByteArray(env, md5Length);
|
||||
if (md5Array == NULL) {
|
||||
// 处理错误
|
||||
EVP_MD_CTX_free(md5Context);
|
||||
(*env)->ReleaseByteArrayElements(env, data_, data, 0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 将 MD5 值复制到 Java 字节数组
|
||||
(*env)->SetByteArrayRegion(env, md5Array, 0, md5Length, (jbyte *) md5Digest);
|
||||
|
||||
// 释放内存和资源
|
||||
EVP_MD_CTX_free(md5Context);
|
||||
(*env)->ReleaseByteArrayElements(env, data_, data, 0);
|
||||
return md5Array;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_lizongying_mytv_Encryptor_init(JNIEnv *env, jobject thiz, jobject context) {
|
||||
// 获取 Context 类
|
||||
jclass contextClass = (*env)->GetObjectClass(env, context);
|
||||
|
||||
// 获取 getAppSignature 方法的 ID
|
||||
jmethodID methodId = (*env)->GetMethodID(env, contextClass, "getAppSignature",
|
||||
"()Ljava/lang/String;");
|
||||
|
||||
// 调用 Kotlin 函数
|
||||
jstring result = (jstring) (*env)->CallObjectMethod(env, context, methodId);
|
||||
|
||||
// 检查 result 是否为 NULL
|
||||
if (result == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 在 C 端处理字符串
|
||||
const char *utfChars = (*env)->GetStringUTFChars(env, result, NULL);
|
||||
|
||||
// 比较签名哈希
|
||||
signatureVerified = (strcmp(utfChars, APP_SIGNATURE) == 0);
|
||||
|
||||
if (signatureVerified == 0 ) {
|
||||
signatureVerified = (strcmp(utfChars, APP_SIGNATURE2) == 0);
|
||||
}
|
||||
|
||||
// 释放字符串
|
||||
(*env)->ReleaseStringUTFChars(env, result, utfChars);
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_com_lizongying_mytv_Encryptor_encrypt(JNIEnv *env, jobject thiz, jstring t, jstring e,
|
||||
jstring r, jstring n, jstring i) {
|
||||
if (signatureVerified == false) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *t_str = (*env)->GetStringUTFChars(env, t, NULL);
|
||||
const char *e_str = (*env)->GetStringUTFChars(env, e, NULL);
|
||||
const char *r_str = (*env)->GetStringUTFChars(env, r, NULL);
|
||||
const char *n_str = (*env)->GetStringUTFChars(env, n, NULL);
|
||||
const char *i_str = (*env)->GetStringUTFChars(env, i, NULL);
|
||||
|
||||
char El[256];
|
||||
snprintf(El, sizeof(El),
|
||||
"|%s|%s|%s|%s|%s|%s|https://www.yangshipin.c|mozilla/5.0 (macintosh; ||Mozilla|Netscape|MacIntel|",
|
||||
t_str, e_str, "mg3c3b04ba", r_str, n_str, i_str);
|
||||
// LOGI("EL %s", El);
|
||||
|
||||
unsigned int xl = 0;
|
||||
for (int Ll = 0; Ll < strlen(El); Ll++) {
|
||||
xl = (xl << 5) - xl + (unsigned char) El[Ll];
|
||||
xl &= xl;
|
||||
}
|
||||
|
||||
char plaintext[256];
|
||||
snprintf(plaintext, sizeof(plaintext), "|%d%s", xl, El);
|
||||
|
||||
// Encrypt the plaintext
|
||||
char *encryptedResult = aes(plaintext);
|
||||
toUpperCase(encryptedResult);
|
||||
|
||||
char result[512];
|
||||
snprintf(result, sizeof(result), "--01%s", encryptedResult);
|
||||
|
||||
// LOGI("result %s", result);
|
||||
|
||||
// Free the memory allocated in the encrypt function
|
||||
free(encryptedResult);
|
||||
|
||||
(*env)->ReleaseStringUTFChars(env, t, t_str);
|
||||
(*env)->ReleaseStringUTFChars(env, e, e_str);
|
||||
(*env)->ReleaseStringUTFChars(env, r, r_str);
|
||||
(*env)->ReleaseStringUTFChars(env, n, n_str);
|
||||
(*env)->ReleaseStringUTFChars(env, i, i_str);
|
||||
|
||||
// Create a Java string from the result and return it
|
||||
jstring resultString = (*env)->NewStringUTF(env, result);
|
||||
|
||||
return resultString;
|
||||
}
|
||||
@@ -61,12 +61,11 @@ class MainFragment : BrowseSupportFragment() {
|
||||
}
|
||||
|
||||
tvListViewModel.getListLiveData().value?.forEach { tvViewModel ->
|
||||
tvViewModel.videoIndex.observe(viewLifecycleOwner) { videoIndex ->
|
||||
if (tvViewModel.getIsFirstTime()) {
|
||||
tvViewModel.isFirstTime(false)
|
||||
} else {
|
||||
tvViewModel.videoUrl.observe(viewLifecycleOwner) { _ ->
|
||||
// Log.i(TAG, "tv ${tvViewModel.getTV()}")
|
||||
if (tvViewModel.updateByYSP()) {
|
||||
val tv = tvViewModel.getTV()
|
||||
if (tvViewModel.id.value == itemPosition) {
|
||||
if (tv.id == itemPosition) {
|
||||
(activity as? MainActivity)?.play(tv)
|
||||
// (activity as? MainActivity)?.switchInfoFragment(tv)
|
||||
}
|
||||
@@ -130,6 +129,7 @@ class MainFragment : BrowseSupportFragment() {
|
||||
|
||||
val tvModel = tvListViewModel.getTVModel(itemPosition)
|
||||
if (tvModel?.ysp() != null) {
|
||||
Log.i(TAG, "ysp ${tvModel.getTV()}")
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
tvModel.let { request?.fetchData(it) }
|
||||
}
|
||||
@@ -171,7 +171,6 @@ class MainFragment : BrowseSupportFragment() {
|
||||
|
||||
val tvModel = tvListViewModel.getTVModel(itemPosition)
|
||||
if (tvModel?.ysp() != null) {
|
||||
Log.i(TAG, "${tvModel.title} to get ysp")
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
tvModel.let { request?.fetchData(it) }
|
||||
}
|
||||
@@ -203,7 +202,6 @@ class MainFragment : BrowseSupportFragment() {
|
||||
|
||||
val tvModel = tvListViewModel.getTVModel(itemPosition)
|
||||
if (tvModel?.ysp() != null) {
|
||||
Log.i(TAG, "${tvModel.title} to get ysp")
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
tvModel.let { request?.fetchData(it) }
|
||||
}
|
||||
@@ -272,7 +270,6 @@ class MainFragment : BrowseSupportFragment() {
|
||||
|
||||
val tvModel = tvListViewModel.getTVModel(itemPosition)
|
||||
if (tvModel?.ysp() != null) {
|
||||
Log.i(TAG, "${tvModel.title} to get ysp")
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
tvModel.let { request?.fetchData(it) }
|
||||
}
|
||||
|
||||
@@ -37,17 +37,17 @@ class Request(var context: Context) {
|
||||
"CCTV10" to "CCTV10 科教",
|
||||
"CCTV11" to "CCTV11 戏曲",
|
||||
"CCTV12" to "CCTV12 社会与法",
|
||||
"CCTV13" to "CCTV13 新闻",
|
||||
// "CCTV13" to "CCTV13",
|
||||
"CCTV14" to "CCTV14 少儿",
|
||||
"CCTV15" to "CCTV15 音乐",
|
||||
"CCTV16-HD" to "CCTV16 奥林匹克",
|
||||
"CCTV17" to "CCTV17 农业农村",
|
||||
"CGTN" to "CGTN",
|
||||
"CGTN外语纪录频道" to "CGTN 纪录频道",
|
||||
"CGTN法语频道" to "CGTN 法语频道",
|
||||
"CGTN俄语频道" to "CGTN 俄语频道",
|
||||
"CGTN阿拉伯语频道" to "CGTN 阿拉伯语频道",
|
||||
"CGTN西班牙语频道" to "CGTN 西班牙语频道",
|
||||
// "CGTN外语纪录频道" to "CGTN外语纪录频道",
|
||||
|
||||
"东方卫视" to "东方卫视",
|
||||
"湖南卫视" to "湖南卫视",
|
||||
@@ -82,7 +82,6 @@ class Request(var context: Context) {
|
||||
|
||||
fun fetchData(tvModel: TVViewModel) {
|
||||
val data = ysp?.switch(tvModel)
|
||||
val title = tvModel.getTV().title
|
||||
|
||||
val request = data?.let { LiveInfoRequest(it) }
|
||||
request?.let { yspApiService?.getLiveInfo(it) }
|
||||
@@ -90,6 +89,7 @@ class Request(var context: Context) {
|
||||
override fun onResponse(call: Call<LiveInfo>, response: Response<LiveInfo>) {
|
||||
if (response.isSuccessful) {
|
||||
val liveInfo = response.body()
|
||||
Log.i(TAG, "liveInfo $liveInfo")
|
||||
if (liveInfo?.data?.playurl != null) {
|
||||
val chanll = liveInfo.data.chanll
|
||||
val decodedBytes = Base64.decode(
|
||||
@@ -99,33 +99,26 @@ class Request(var context: Context) {
|
||||
val decodedString = String(decodedBytes)
|
||||
val regex = Regex("""des_key = "([^"]+).+var des_iv = "([^"]+)""")
|
||||
val matchResult = regex.find(decodedString)
|
||||
var keyBytes = byteArrayOf()
|
||||
var ivBytes = byteArrayOf()
|
||||
|
||||
if (matchResult != null) {
|
||||
val (key, iv) = matchResult.destructured
|
||||
val keyBytes = Base64.decode(key, Base64.DEFAULT)
|
||||
val ivBytes = Base64.decode(iv, Base64.DEFAULT)
|
||||
val url = liveInfo.data.playurl + "&revoi=" + encryptTripleDES(
|
||||
keyBytes = Base64.decode(key, Base64.DEFAULT)
|
||||
ivBytes = Base64.decode(iv, Base64.DEFAULT)
|
||||
}
|
||||
tvModel.updateVideoUrlByYSP(
|
||||
liveInfo.data.playurl + "&revoi=" + encryptTripleDES(
|
||||
keyBytes + byteArrayOf(0, 0, 0, 0, 0, 0, 0, 0),
|
||||
ivBytes
|
||||
).uppercase()
|
||||
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()
|
||||
)
|
||||
}
|
||||
} else {
|
||||
Log.e(TAG, "$title status error")
|
||||
tvModel.firstSource()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(call: Call<LiveInfo>, t: Throwable) {
|
||||
Log.e(TAG, "${tvModel.getTV().title} request error")
|
||||
tvModel.firstSource()
|
||||
Log.i(TAG, "get data error")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.lizongying.mytv
|
||||
|
||||
import android.util.Log
|
||||
|
||||
object TVList {
|
||||
val list: Map<String, Map<String, TV>> by lazy {
|
||||
setupTV()
|
||||
@@ -15,31 +17,34 @@ CCTV1 综合,http://tvpull.dxhmt.cn/tv/11481-4.m3u8,https://resources.yangshipin
|
||||
CCTV2 财经,http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226195/index.m3u8,https://resources.yangshipin.cn/assets/oms/image/202306/20115388de0207131af17eac86c33049b95d69eaff064e55653a1b941810a006.png?imageMogr2/format/webp,600001800,2000203603
|
||||
CCTV3 综艺,http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226397/index.m3u8
|
||||
CCTV4 中文国际,http://39.134.24.161/dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226191/index.m3u8;http://hlsbkmgsplive.miguvideo.com/wd_r2/cctv/cctv4hd/1500/index.m3u8?&encrypt=,https://resources.yangshipin.cn/assets/oms/image/202306/f357e58fdbcc076a3d65e1f958c942b2e14f14342c60736ceed98b092d35356a.png?imageMogr2/format/webp,600001814,2000204803
|
||||
CCTV5 体育,http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226395/index.m3u8,https://resources.yangshipin.cn/assets/oms/image/202306/0a6a7138952675983a3d854df7688557b286d59aa06166edae51506f9204d655.png?imageMogr2/format/webp,600001818,2000205103
|
||||
CCTV5+ 体育赛事,http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226221/index.m3u8,https://resources.yangshipin.cn/assets/oms/image/202306/649ad76a90bfef55b05db9fe52e006487280f619089099d5dc971e387fc6eff0.png?imageMogr2/format/webp,600001817,2000204503
|
||||
CCTV6 电影,http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226393/index.m3u8
|
||||
CCTV7 国防军事,http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226192/index.m3u8,https://resources.yangshipin.cn/assets/oms/image/202306/b29af94e295ebdf646cefb68122c429b9cd921f498ca20d2d8070252536f9ff9.png?imageMogr2/format/webp,600004092,2000510003
|
||||
CCTV8 电视剧,http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226391/index.m3u8
|
||||
CCTV9 记录,http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226197/index.m3u8,https://resources.yangshipin.cn/assets/oms/image/202306/2ed1b4deeca179d5db806bb941790f82eb92a1b7299c1c38fe027f95a5caee5e.png?imageMogr2/format/webp,600004078,2000499403
|
||||
CCTV10 科教,http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226189/index.m3u8,https://resources.yangshipin.cn/assets/oms/image/202306/aa6157ec65188cd41826e5a2f088c3d6d153205f5f6428258d12c59999e221aa.png?imageMogr2/format/webp,600001805,2000203503
|
||||
CCTV11 戏曲,http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226240/index.m3u8,https://resources.yangshipin.cn/assets/oms/image/202306/ed12ed7c7a1034dae4350011fe039284c5d5a836506b28c9e32e3c75299625c0.png?imageMogr2/format/webp,600001806,2000204103
|
||||
CCTV12 社会与法,http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226190/index.m3u8, https://resources.yangshipin.cn/assets/oms/image/202306/484083cffaa40df7e659565e8cb4d1cc740158a185512114167aa21fa0c59240.png?imageMogr2/format/webp,600001807,2000202603
|
||||
CCTV13 新闻,https://live-play.cctvnews.cctv.com/cctv/merge_cctv13.m3u8
|
||||
CCTV14 少儿,http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226193/index.m3u8,https://resources.yangshipin.cn/assets/oms/image/202306/af6b603896938dc346fbb16abfc63c12cba54b0ec9d18770a15d347d115f12d5.png?imageMogr2/format/webp,600001809,2000204403
|
||||
CCTV15 音乐,http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225785/index.m3u8,https://resources.yangshipin.cn/assets/oms/image/202306/2ceee92188ef684efe0d8b90839c4f3ad450d179dc64d59beff417059453af47.png?imageMogr2/format/webp,600001815,2000205003
|
||||
CCTV4 中文国际美洲,http://hlsbkmgsplive.miguvideo.com/migu/kailu/20200324/cctv4meihd/57/index.m3u8?&encrypt=
|
||||
CCTV4 中文国际欧洲,http://hlsbkmgsplive.miguvideo.com/migu/kailu/20200324/cctv4ouhd/51/index.m3u8?&encrypt=
|
||||
CCTV5 体育,http://hlsbkmgsplive.miguvideo.com/migu/kailu/cctv5hd265/57/20191230/index.m3u8?&encrypt=,https://resources.yangshipin.cn/assets/oms/image/202306/0a6a7138952675983a3d854df7688557b286d59aa06166edae51506f9204d655.png?imageMogr2/format/webp,600001818,2000205103
|
||||
CCTV5+ 体育赛事,http://hlsbkmgsplive.miguvideo.com/wd_r2/cctv/cctv5plusnew/2500/index.m3u8?&encrypt=,https://resources.yangshipin.cn/assets/oms/image/202306/649ad76a90bfef55b05db9fe52e006487280f619089099d5dc971e387fc6eff0.png?imageMogr2/format/webp,600001817,2000204503
|
||||
CCTV6 电影,http://hlsbkmgsplive.miguvideo.com/wd_r2/ocn/cctv6hd/3000/index.m3u8?&encrypt=
|
||||
CCTV7 国防军事,http://hlsbkmgsplive.miguvideo.com/migu/kailu/20200324/cctv7hd/51/index.m3u8?&encrypt=,https://resources.yangshipin.cn/assets/oms/image/202306/b29af94e295ebdf646cefb68122c429b9cd921f498ca20d2d8070252536f9ff9.png?imageMogr2/format/webp,600004092,2000510003
|
||||
CCTV8 电视剧,http://hlsbkmgsplive.miguvideo.com/wd_r2/ocn/cctv8hd/3000/index.m3u8?&encrypt=
|
||||
CCTV9 记录,http://hlsbkmgsplive.miguvideo.com/migu/kailu/20200324/cctv9hd/57/index.m3u8?&encrypt=,https://resources.yangshipin.cn/assets/oms/image/202306/2ed1b4deeca179d5db806bb941790f82eb92a1b7299c1c38fe027f95a5caee5e.png?imageMogr2/format/webp,600004078,2000499403
|
||||
CCTV10 科教,http://hlsbkmgsplive.miguvideo.com/wd_r2/2018/ocn/cctv10hd/2000/index.m3u8?&encrypt=,https://resources.yangshipin.cn/assets/oms/image/202306/aa6157ec65188cd41826e5a2f088c3d6d153205f5f6428258d12c59999e221aa.png?imageMogr2/format/webp,600001805,2000203503
|
||||
CCTV11 戏曲,http://hlsbkmgsplive.miguvideo.com/migu/kailu/cctv11hd/57/20200103/index.m3u8?&encrypt=,https://resources.yangshipin.cn/assets/oms/image/202306/ed12ed7c7a1034dae4350011fe039284c5d5a836506b28c9e32e3c75299625c0.png?imageMogr2/format/webp,600001806,2000204103
|
||||
CCTV12 社会与法,http://hlsbkmgsplive.miguvideo.com/migu/kailu/20200324/cctv12hd/57/index.m3u8?&encrypt=, https://resources.yangshipin.cn/assets/oms/image/202306/484083cffaa40df7e659565e8cb4d1cc740158a185512114167aa21fa0c59240.png?imageMogr2/format/webp,600001807,2000202603
|
||||
CCTV13 新闻,https://live-play.cctvnews.cctv.com/cctv/merge_cctv13.m3u8;http://hlsbkmgsplive.miguvideo.com/envivo_x/2018/SD/cctv13/2000/index.m3u8?&encrypt=
|
||||
CCTV14 少儿,http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226193/index.m3u8;http://hlsbkmgsplive.miguvideo.com/wd_r2/ocn/cctv14hd/3000/index.m3u8?&encrypt=,https://resources.yangshipin.cn/assets/oms/image/202306/af6b603896938dc346fbb16abfc63c12cba54b0ec9d18770a15d347d115f12d5.png?imageMogr2/format/webp,600001809,2000204403
|
||||
CCTV15 音乐,http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221225785/index.m3u8;http://hlsbkmgsplive.miguvideo.com/migu/kailu/20200324/cctv15hd/51/index.m3u8?&encrypt=,https://resources.yangshipin.cn/assets/oms/image/202306/2ceee92188ef684efe0d8b90839c4f3ad450d179dc64d59beff417059453af47.png?imageMogr2/format/webp,600001815,2000205003
|
||||
CCTV16 奥林匹克,http://39.134.24.162/dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226921/index.m3u8,https://resources.yangshipin.cn/assets/oms/image/202306/53793fa7bacd3a93ff6dc5d2758418985e1f952a316c335d663b572d8bdcd74d.png?imageMogr2/format/webp,600098637,2012375003
|
||||
CCTV17 农业农村,http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226198/index.m3u8,https://resources.yangshipin.cn/assets/oms/image/202306/ddef563072f8bad2bea5b9e52674cb7b4ed50efb20c26e61994dfbdf05c1e3c0.png?imageMogr2/format/webp,600001810,2000204203
|
||||
CGTN,,https://resources.yangshipin.cn/assets/oms/image/202306/a72dff758ca1c17cd0ecc8cedc11b893d208f409d5e6302faa0e9d298848abc3.png?imageMogr2/format/webp,600014550,2001656803
|
||||
CCTV17 农业农村,http://hlsbkmgsplive.miguvideo.com/migu/kailu/20200324/cctv17hd/57/index.m3u8?&encrypt=,https://resources.yangshipin.cn/assets/oms/image/202306/ddef563072f8bad2bea5b9e52674cb7b4ed50efb20c26e61994dfbdf05c1e3c0.png?imageMogr2/format/webp,600001810,2000204203
|
||||
CGTN,http://hlsbkmgsplive.miguvideo.com/envivo_x/2018/SD/cctvnews/1000/index.m3u8?&encrypt=,https://resources.yangshipin.cn/assets/oms/image/202306/a72dff758ca1c17cd0ecc8cedc11b893d208f409d5e6302faa0e9d298848abc3.png?imageMogr2/format/webp,600014550,2001656803
|
||||
CGTN 新闻频道,http://live.cgtn.com/1000/prog_index.m3u8
|
||||
CGTN 纪录频道,https://livedoc.cgtn.com/500d/prog_index.m3u8
|
||||
CGTN 法语频道,https://livefr.cgtn.com/1000f/prog_index.m3u8,https://resources.yangshipin.cn/assets/oms/image/202306/a8d0046a47433d952bf6ed17062deb8bd2184ba9aec0f7781df6bf9487a3ffcf.png?imageMogr2/format/webp,600084704,2010153503
|
||||
CGTN 俄语频道,http://liveru.cgtn.com/1000r/prog_index.m3u8,https://resources.yangshipin.cn/assets/oms/image/202306/bf0a820893cbaf20dd0333e27042e1ef9c8806e5b602b6a8c95af399db0bc77a.png?imageMogr2/format/webp,600084758,2010152603
|
||||
CGTN 西班牙语频道,http://livees.cgtn.com/500e/prog_index.m3u8;http://livees.cgtn.com/1000e/prog_index.m3u8,https://resources.yangshipin.cn/assets/oms/image/202309/7c337e3dbe64402ec7e4678a619a4a6d95144e42f35161181ff78e143b7cf67a.png?imageMogr2/format/webp,600084744,2010152503
|
||||
CGTN 西班牙语频道,http://livees.cgtn.com/500e/prog_index.m3u8,https://resources.yangshipin.cn/assets/oms/image/202309/7c337e3dbe64402ec7e4678a619a4a6d95144e42f35161181ff78e143b7cf67a.png?imageMogr2/format/webp,600084744,2010152503
|
||||
CGTN 阿拉伯语频道,http://livear.cgtn.com/1000a/prog_index.m3u8,https://resources.yangshipin.cn/assets/oms/image/202306/2e44e2aa3e7a1cedf07fd0ae59fe69e86a60a2632660a006e3e9e7397b2d107e.png?imageMogr2/format/webp,600084782,2010155203
|
||||
CGTN 拉丁美洲频道,http://livees.cgtn.com/1000e/prog_index.m3u8
|
||||
书画频道,http://211.103.180.178:8234/live_hls/hdmi.m3u8
|
||||
|
||||
地方频道
|
||||
东方卫视,http://dbiptv.sn.chinamobile.com/PLTV/88888890/224/3221226217/index.m3u8,https://resources.yangshipin.cn/assets/oms/image/202306/9bd372ca292a82ce3aa08772b07efc4af1f85c21d1f268ea33440c49e9a0a488.png?imageMogr2/format/webp,600002483,2000292403
|
||||
东方卫视,,https://resources.yangshipin.cn/assets/oms/image/202306/9bd372ca292a82ce3aa08772b07efc4af1f85c21d1f268ea33440c49e9a0a488.png?imageMogr2/format/webp,600002483,2000292403
|
||||
内蒙古卫视,http://ottrrs.hl.chinamobile.com/PLTV/88888888/224/3221226389/index.m3u8
|
||||
湖南卫视,http://ottrrs.hl.chinamobile.com/PLTV/88888888/224/3221226307/index.m3u8,https://resources.yangshipin.cn/assets/oms/image/202306/4120e89d3079d08aa17d382f69a2308ec70839b278367763c34a34666c75cb88.png?imageMogr2/format/webp,600002475,2000296203
|
||||
湖北卫视,http://ottrrs.hl.chinamobile.com/PLTV/88888888/224/3221226477/index.m3u8,https://resources.yangshipin.cn/assets/oms/image/202306/7a6be5a2bb1dc53a945c016ff1f525dc4a84c51db371c15c89aa55404b0ba784.png?imageMogr2/format/webp,600002508,2000294503
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.lizongying.mytv.models
|
||||
|
||||
import android.util.Log
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
@@ -9,7 +8,7 @@ import com.lizongying.mytv.TV
|
||||
class TVViewModel(private var tv: TV) : ViewModel() {
|
||||
private var mapping = mapOf(
|
||||
"CCTV4K" to "CCTV4K",
|
||||
"CCTV1" to "CCTV1 综合",
|
||||
// "CCTV1" to "CCTV1 综合",
|
||||
"CCTV2" to "CCTV2 财经",
|
||||
"CCTV4" to "CCTV4 中文国际",
|
||||
"CCTV5" to "CCTV5 体育",
|
||||
@@ -19,17 +18,17 @@ class TVViewModel(private var tv: TV) : ViewModel() {
|
||||
"CCTV10" to "CCTV10 科教",
|
||||
"CCTV11" to "CCTV11 戏曲",
|
||||
"CCTV12" to "CCTV12 社会与法",
|
||||
"CCTV13" to "CCTV13 新闻",
|
||||
// "CCTV13" to "CCTV13",
|
||||
"CCTV14" to "CCTV14 少儿",
|
||||
"CCTV15" to "CCTV15 音乐",
|
||||
"CCTV16-HD" to "CCTV16 奥林匹克",
|
||||
"CCTV17" to "CCTV17 农业农村",
|
||||
"CGTN" to "CGTN",
|
||||
"CGTN外语纪录频道" to "CGTN 纪录频道",
|
||||
"CGTN法语频道" to "CGTN 法语频道",
|
||||
"CGTN俄语频道" to "CGTN 俄语频道",
|
||||
"CGTN阿拉伯语频道" to "CGTN 阿拉伯语频道",
|
||||
"CGTN西班牙语频道" to "CGTN 西班牙语频道",
|
||||
// "CGTN外语纪录频道" to "CGTN外语纪录频道",
|
||||
|
||||
"东方卫视" to "东方卫视",
|
||||
"湖南卫视" to "湖南卫视",
|
||||
@@ -54,24 +53,12 @@ class TVViewModel(private var tv: TV) : ViewModel() {
|
||||
"海南卫视" to "海南卫视",
|
||||
).entries.associate { (key, value) -> value to key }
|
||||
|
||||
private var isFirstTime = true
|
||||
|
||||
private val _id = MutableLiveData<Int>()
|
||||
val id: LiveData<Int>
|
||||
get() = _id
|
||||
|
||||
private val _title = MutableLiveData<String>()
|
||||
val title: LiveData<String>
|
||||
get() = _title
|
||||
private var updateByYSP = false
|
||||
|
||||
private val _videoUrl = MutableLiveData<List<String>>()
|
||||
val videoUrl: LiveData<List<String>>
|
||||
get() = _videoUrl
|
||||
|
||||
private val _videoIndex = MutableLiveData<Int>()
|
||||
val videoIndex: LiveData<Int>
|
||||
get() = _videoIndex
|
||||
|
||||
private val _pid = MutableLiveData<String>()
|
||||
val pid: LiveData<String>
|
||||
get() = _pid
|
||||
@@ -92,37 +79,25 @@ class TVViewModel(private var tv: TV) : ViewModel() {
|
||||
_backgroundImage.value = url
|
||||
}
|
||||
|
||||
fun addVideoUrl(url: String) {
|
||||
tv.videoUrl = tv.videoUrl + listOf(url)
|
||||
tv.videoIndex = tv.videoUrl.lastIndex
|
||||
_videoUrl.value = tv.videoUrl
|
||||
_videoIndex.value = tv.videoIndex
|
||||
private fun updateVideoUrl(url: String) {
|
||||
tv.videoUrl = listOf(url)
|
||||
tv.videoIndex = 0
|
||||
_videoUrl.value = listOf(url)
|
||||
}
|
||||
|
||||
fun firstSource() {
|
||||
if (tv.videoUrl.isNotEmpty()) {
|
||||
tv.videoIndex = 0
|
||||
_videoIndex.value = 0
|
||||
} else {
|
||||
Log.e(TAG, "no first")
|
||||
}
|
||||
fun updateVideoUrlByYSP(url: String) {
|
||||
updateByYSP = true
|
||||
updateVideoUrl(url)
|
||||
}
|
||||
|
||||
init {
|
||||
_id.value = tv.id
|
||||
_title.value = tv.title
|
||||
_videoUrl.value = tv.videoUrl
|
||||
_videoIndex.value = tv.videoIndex
|
||||
_pid.value = tv.pid
|
||||
_sid.value = tv.sid
|
||||
}
|
||||
|
||||
fun getIsFirstTime(): Boolean {
|
||||
return isFirstTime
|
||||
}
|
||||
|
||||
fun isFirstTime(firstTime: Boolean) {
|
||||
isFirstTime = firstTime
|
||||
fun updateByYSP(): Boolean {
|
||||
return updateByYSP
|
||||
}
|
||||
|
||||
fun update(t: TV) {
|
||||
@@ -139,8 +114,4 @@ class TVViewModel(private var tv: TV) : ViewModel() {
|
||||
}
|
||||
return mapping[tv.title]
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "TVViewModel"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- res/layout/custom_browse_fragment.xml -->
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/right_content_frame"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_toRightOf="@+id/browse_headers" />
|
||||
|
||||
<fragment
|
||||
android:id="@+id/browse_headers"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_alignParentLeft="true" />
|
||||
</RelativeLayout>
|
||||
Reference in New Issue
Block a user