Compare commits

...
11 Commits
Author SHA1 Message Date
Li ZongYing f4c1db33b3 ysp 2024-06-07 13:13:05 +08:00
Li ZongYing e55584c910 Balanced sounds 2024-06-03 18:17:43 +08:00
Li ZongYing cf8d7f00a8 fix ysp 2024-05-31 11:10:18 +08:00
Li ZongYing bcfca9e28c fix gson crash 2024-05-27 14:13:34 +08:00
Li ZongYing 31ec13eed7 fix gson crash 2024-05-26 20:50:08 +08:00
Li ZongYing 5a78913407 fix gson crash 2024-05-26 20:49:01 +08:00
Li ZongYing bb38cf5033 fix gson crash 2024-05-26 20:20:42 +08:00
Li ZongYing 51d9c4c2a7 fix gson crash 2024-05-26 20:16:10 +08:00
Li ZongYing 70da1d8241 fix the settings options are not displayed 2024-05-26 09:36:24 +08:00
Li ZongYing ef17427f64 add reset 2024-05-21 09:55:15 +08:00
Li ZongYing c1143afb4e fix ysp 2024-05-20 22:23:16 +08:00
48 changed files with 716 additions and 525 deletions
+195 -168
View File
@@ -1,246 +1,273 @@
## 更新日志 ## 更新日誌
### v2.0.3 ### v2.1.2
* 修复不能播放的问题 *
### v2.0.0 ### v2.1.1
* 解决卡顿问题 * 平衡聲音
* 解决网格样式时,点击空白处不退出的问题
* 解决频道列表样式切换可能不生效的问题
### v1.9.8(通用) ### v2.1.0
* 优化在线升级 * 恢復播放
* 优化可能状态错误的问题
### v1.9.6(通用)
* 优化在线升级
* 优化可能状态错误的问题
### v1.9.4(通用)
* 修复默认时间不显示问题
* 设置页居中
* 频道号和时间对齐
### v1.9.2(通用)
* 修复一个重试的错误
### v1.9.0(通用)
* 减少视频播放失败情况
* 全面屏手机居中显示
### v1.8.8(通用)
* 样式优化
### v1.8.6(通用)
* 增加错误显示
* 节目预告优化
* 频道列表页单击切换频道
### v1.8.4(通用)
* 解決部分情況下打開後黑屏问题
* 延长频道信息显示时间,增加信息显示长度
* 调整频道列表间距
* 其他样式优化
### v1.8.2(通用)
* 修复无法播放问题
### 以下已不可用 ### 以下已不可用
### v2.0.9
* 修復部分設備閃退的問題
* 修復設置頁可能顯示不全的問題
### v2.0.5
* 設置頁增加恢復默認按鈕,目前只用於同步系統時間
### v2.0.4
* 修復不能播放的問題
* 包含國際頻道
### v2.0.3
* 修復不能播放的問題
* 不包含國際頻道
### v2.0.0
* 解決卡頓問題
* 解決網格樣式時,點擊空白處不退出的問題
* 解決頻道列表樣式切換可能不生效的問題
### v1.9.8(通用)
* 優化在線升級
* 優化可能狀態錯誤的問題
### v1.9.6(通用)
* 優化在線升級
* 優化可能狀態錯誤的問題
### v1.9.4(通用)
* 修復默認時間不顯示問題
* 設置頁居中
* 頻道號和時間對齊
### v1.9.2(通用)
* 修復一個重試的錯誤
### v1.9.0(通用)
* 減少視頻播放失敗情況
* 全面屏手機居中顯示
### v1.8.8(通用)
* 樣式優化
### v1.8.6(通用)
* 增加錯誤顯示
* 節目預告優化
* 頻道列表頁單擊切換頻道
### v1.8.4(通用)
* 解決部分情況下打開後黑屏問題
* 延長頻道信息顯示時間,增加信息顯示長度
* 調整頻道列表間距
* 其他樣式優化
### v1.8.2(通用)
* 修復無法播放問題
### v1.8.0(通用) ### v1.8.0(通用)
* 修复返回键无法退出问题 * 修復返回鍵無法退出問題
* 设置中增加退出按钮 * 設置中增加退出按鈕
* 修改非电视上的样式 * 修改非電視上的樣式
* 修复低版本闪退问题 * 修復低版本閃退問題
### v1.7.8(通用) ### v1.7.8(通用)
* 修复播放过程中的卡顿问题 * 修復播放過程中的卡頓問題
* 增加时间显示 * 增加時間顯示
* 频道号优化 * 頻道號優化
* 遥控器左键打开频道列表 * 遙控器左鍵打開頻道列表
* 遥控器右键打开设置菜单 * 遙控器右鍵打開設置菜單
* 频道列表空白处点击隐藏频道列表 * 頻道列表空白處點擊隱藏頻道列表
### v1.7.6(通用) ### v1.7.6(通用)
* 临时去掉部分频道,提高频道的可用性 * 臨時去掉部分頻道,提高頻道的可用性
* 部分频道增加节目单 * 部分頻道增加節目單
### v1.7.5(安卓5及以上专用) ### v1.7.5(安卓5及以上專用)
* 修复播放过程中的卡顿问题 * 修復播放過程中的卡頓問題
* 增加时间显示 * 增加時間顯示
* 频道号优化 * 頻道號優化
* 设置中增加退出按钮 * 設置中增加退出按鈕
### v1.7.4(通用) ### v1.7.4(通用)
* 修复368 * 修復368
### v1.7.3(安卓5及以上专用) ### v1.7.3(安卓5及以上專用)
* 临时去掉部分频道,提高频道的可用性 * 臨時去掉部分頻道,提高頻道的可用性
* 部分频道增加节目单 * 部分頻道增加節目單
* 遥控器左键进入节目列表 * 遙控器左鍵進入節目列表
* 遥控器右键进入菜单 * 遙控器右鍵進入菜單
### v1.7.2(通用) ### v1.7.2(通用)
* 支持节目列表网格样式和行样式切换,软件重启后生效 * 支持節目列表網格樣式和行樣式切換,軟件重啟後生效
* 节目列表样式变更 * 節目列表樣式變更
### v1.7.1(安卓5及以上专用) ### v1.7.1(安卓5及以上專用)
* 解决设置页更新闪退的问题 * 解決設置頁更新閃退的問題
* 凤凰卫视回归 * 鳳凰衛視回歸
* 解决368问题 * 解決368問題
### v1.7.0(通用) ### v1.7.0(通用)
* 网络请求优化 * 網絡請求優化
### v1.6.9(安卓5及以上专用) ### v1.6.9(安卓5及以上專用)
* 去掉港澳台和国际频道 * 去掉港澳台和國際頻道
* 解决部分情况下3、6、8等频道无法播放的问题 * 解決部分情況下3、6、8等頻道無法播放的問題
* 解决部分情况下启动后黑屏问题 * 解決部分情況下啟動後黑屏問題
### v1.6.8(通用) ### v1.6.8(通用)
* 修复部分设备崩溃的问题 * 修復部分設備崩潰的問題
* 修复部分设备凤凰卫视无法播放的问题 * 修復部分設備鳳凰衛視無法播放的問題
### v1.6.7(安卓5及以上专用) ### v1.6.7(安卓5及以上專用)
* 手机双击打开配置 * 手機雙擊打開配置
* 自动更新 * 自動更新
### v1.6.6(通用) ### v1.6.6(通用)
* 更新重庆卫视图标 * 更新重慶衛視圖標
* 凤凰卫视增强画质 * 鳳凰衛視增強畫質
* 凤凰卫视增加EPG * 鳳凰衛視增加EPG
### v1.6.5(安卓5及以上专用) ### v1.6.5(安卓5及以上專用)
* 增加CETV1图标 * 增加CETV1圖標
* 稳定性提升 * 穩定性提升
### v1.6.4(通用) ### v1.6.4(通用)
* 增加CETV1 * 增加CETV1
* 增加凤凰卫视 * 增加鳳凰衛視
* 默认关闭开机启动 * 默認關閉開機啟動
### v1.6.3(安卓5及以上专用) ### v1.6.3(安卓5及以上專用)
* 增加CETV1 * 增加CETV1
* 凤凰卫视增强画质 * 鳳凰衛視增強畫質
* 默认关闭开机启动 * 默認關閉開機啟動
* 延迟菜单自动关闭时间 * 延遲菜單自動關閉時間
* 解决一些可能导致首次打开时黑屏的问题 * 解決一些可能導致首次打開時黑屏的問題
### v1.6.2(通用) ### v1.6.2(通用)
* 修复按键无效的问题 * 修復按鍵無效的問題
* 新的频道列表样式 * 新的頻道列表樣式
### v1.6.1(安卓5及以上专用) ### v1.6.1(安卓5及以上專用)
* 增加凤凰卫视 * 增加鳳凰衛視
### v1.6.0(通用) ### v1.6.0(通用)
* 通用(春晚緊急修復) * 通用(春晚緊急修復)
### v1.5.9(安卓5及以上专用) ### v1.5.9(安卓5及以上專用)
* 解决天猫魔盒闪退问题 * 解決天貓魔盒閃退問題
### v1.5.8(通用) ### v1.5.8(通用)
* 修复央视6画质差的问题 * 修復央視6畫質差的問題
* 增加兵团卫视 * 增加兵團衛視
* 播放失败重试 * 播放失敗重試
### v1.5.7(安卓5及以上专用) ### v1.5.7(安卓5及以上專用)
* 修复播放失败的问题 * 修復播放失敗的問題
### v1.5.6(通用) ### v1.5.6(通用)
* 解决部分设备系统时间不对导致播放失败的问题 * 解決部分設備系統時間不對導致播放失敗的問題
### v1.5.5(安卓5及以上专用) ### v1.5.5(安卓5及以上專用)
* 修复播放失败的问题 * 修復播放失敗的問題
* 修复APP恢复后频道号、频道列表不自动消失的问题 * 修復APP恢復後頻道號、頻道列表不自動消失的問題
### v1.5.4(通用) ### v1.5.4(通用)
* 修复播放失败的问题 * 修復播放失敗的問題
### v1.5.3(安卓5及以上专用) ### v1.5.3(安卓5及以上專用)
* 修复部分情况下APP切换后无法继续播放的问题 * 修復部分情況下APP切換後無法繼續播放的問題
* 优化重试逻辑 * 優化重試邏輯
### v1.5.2(通用) ### v1.5.2(通用)
* 修复APP恢复后频道号、频道列表不自动消失的问题 * 修復APP恢復後頻道號、頻道列表不自動消失的問題
### v1.5.1(安卓5及以上专用) ### v1.5.1(安卓5及以上專用)
* 性能优化 * 性能優化
### v1.5.0(通用) ### v1.5.0(通用)
* 修复部分情况下APP切换后无法继续播放的问题 * 修復部分情況下APP切換後無法繼續播放的問題
### v1.4.9(安卓5及以上专用) ### v1.4.9(安卓5及以上專用)
* 同步v1.4.8 * 同步v1.4.8
### v1.4.8(通用) ### v1.4.8(通用)
* 频道号从1开始,CCTV5+为18 * 頻道號從1開始,CCTV5+為18
* 提高CCTV6清晰度 * 提高CCTV6清晰度
* 增加天津卫视、新疆卫视 * 增加天津衛視、新疆衛視
### v1.4.7(安卓5及以上专用) ### v1.4.7(安卓5及以上專用)
* 修复部分用户CCTV13播放过程中卡住的问题 * 修復部分用戶CCTV13播放過程中卡住的問題
* 调整CCTV的频道顺序 * 調整CCTV的頻道順序
### v1.4.6(通用) ### v1.4.6(通用)
* 10以下频道不再需要先按0 * 10以下頻道不再需要先按0
### v1.4.5(安卓5及以上专用) ### v1.4.5(安卓5及以上專用)
* 数字选台配置 * 數字選台配置
### v1.4.4(通用) ### v1.4.4(通用)
* 优化图标显示 * 優化圖標顯示
* 增加换台反转 * 增加換台反轉
### v1.4.3(安卓5及以上专用) ### v1.4.3(安卓5及以上專用)
* 支持频道反转配置 * 支持頻道反轉配置
### v1.4.2(通用) ### v1.4.2(通用)
@@ -248,40 +275,40 @@
### v1.4.1 ### v1.4.1
* 解决部分用户无法打开菜单的问题 * 解決部分用戶無法打開菜單的問題
### v1.4.0 ### v1.4.0
* 解决极个别高版本机型黑屏问题 * 解決極個別高版本機型黑屏問題
### v1.3.9 ### v1.3.9
* 提高稳定性 * 提高穩定性
* 提高连接速度 * 提高連接速度
### v1.3.4 ### v1.3.4
* 部分错误会提示用户 * 部分錯誤會提示用戶
* 菜单3秒钟后自动关闭 * 菜單3秒鐘後自動關閉
### v1.3.3 ### v1.3.3
* 部分错误会提示用户 * 部分錯誤會提示用戶
* 菜单3秒钟后自动关闭 * 菜單3秒鐘後自動關閉
### v1.3.2 ### v1.3.2
* 增加重试,减少因网络问题导致的播放失败 * 增加重試,減少因網絡問題導致的播放失敗
* 优化横幅banner * 優化橫幅banner
### v1.3.1 ### v1.3.1
* 增加CCTV 8K 超高清频道 * 增加CCTV 8K 超高清頻道
* 增加国际频道栏目 * 增加國際頻道欄目
### v1.3.0 ### v1.3.0
* 处理368可能失败的情形 * 處理368可能失敗的情形
### v1.2.9 ### v1.2.9
@@ -293,32 +320,32 @@
### v1.2.7 ### v1.2.7
* 此版本是为了测试安卓6.0以下版本,如之前可以正常运行,请勿安装。 * 此版本是為了測試安卓6.0以下版本,如之前可以正常運行,請勿安裝。
### v1.2.6 ### v1.2.6
* 支持安卓4.2 * 支持安卓4.2
* 解决部分频道无法播放的问题 * 解決部分頻道無法播放的問題
* 修复切换时有时没有恢复播放的问题 * 修復切換時有時沒有恢復播放的問題
* 左右键不再切换源 * 左右鍵不再切換源
* 增大频道信息标题尺寸,缩小与节目信息的间隔 * 增大頻道信息標題尺寸,縮小與節目信息的間隔
### v1.2.5 ### v1.2.5
* 美化频道信息显示 * 美化頻道信息顯示
* 优化节目单获取 * 優化節目單獲取
### v1.2.4 ### v1.2.4
* 改变换台滑动方向,上一个频道下滑,下一个频道上滑 * 改變換台滑動方向,上一個頻道下滑,下一個頻道上滑
* 软件退出时,退出播放器 * 軟件退出時,退出播放器
* 播放相同的频道,不再重复加载 * 播放相同的頻道,不再重複加載
* 暂时移除部分频道 * 暫時移除部分頻道
### v1.2.3 ### v1.2.3
* 固定视频比列为16:9 * 固定視頻比例為16:9
* 隐藏全面屏底部的小横条 * 隱藏全面屏底部的小橫條
* 移除移动专区 * 移除移動專區
* 修复一个闪退问题 * 修復一個閃退問題
* 更换图标和应用名 * 更換圖標和應用名
+1 -1
View File
@@ -16,4 +16,4 @@ gen-version:
#make gen v=v2.0.0 #make gen v=v2.0.0
gen: gen:
echo $(v) | sed 's/v/ /g' | sed 's/\./ /g' | sed 's/-/ /g' | awk '{print "{\"version_code\": " ($$1*16777216)+($$2*65536)+($$3*256)+$$4 ", \"version_name\": \"" "$(v)" "\"}"}' > version.json echo $(v) | sed 's/v/ /g' | sed 's/\./ /g' | sed 's/-/ /g' | awk '{print "{\"version_code\": " ($$1*16777216)+($$2*65536)+($$3*256)+$$4 ", \"version_name\": \"" "v$(v)" "\"}"}' > version.json
-1
View File
@@ -35,7 +35,6 @@
* 亮度调节 * 亮度调节
* 音量调节 * 音量调节
* 軟解 * 軟解
* 网格空白处退出
## 版权说明 ## 版权说明
+1
View File
@@ -4,3 +4,4 @@
/CMakeFiles/ /CMakeFiles/
/Makefile /Makefile
/src/main/cpp/native.c /src/main/cpp/native.c
/src/main/cpp/aes.c
+3 -1
View File
@@ -21,7 +21,9 @@ if (IS_SO_BUILD)
SHARED SHARED
# Provides a relative path to your source file(s). # Provides a relative path to your source file(s).
src/main/cpp/native.c) src/main/cpp/native.c
src/main/cpp/aes.c
)
# 设置编译输出路径 # 设置编译输出路径
set_target_properties( set_target_properties(
+38 -7
View File
@@ -26,6 +26,7 @@ android {
cmake { 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 : true}"
// abiFilters "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
abiFilters "armeabi-v7a", "arm64-v8a" abiFilters "armeabi-v7a", "arm64-v8a"
} }
} }
@@ -89,7 +90,7 @@ static def VersionName() {
process.waitFor() process.waitFor()
def versionName = process.text.trim() - "v" def versionName = process.text.trim() - "v"
if (versionName.isEmpty()) { if (versionName.isEmpty()) {
versionName = "1.0.0" versionName = "1.0.0"
} }
return versionName return versionName
} catch (ignored) { } catch (ignored) {
@@ -97,6 +98,10 @@ static def VersionName() {
} }
} }
def gson_version = "2.10.1"
def failureaccess_version = "1.0.2"
def guava_version = "33.2.1-android"
dependencies { dependencies {
// minSdk17 // minSdk17
@@ -105,7 +110,13 @@ dependencies {
implementation "androidx.media3:media3-ui:$media3_version" implementation "androidx.media3:media3-ui:$media3_version"
// For media playback using ExoPlayer // For media playback using ExoPlayer
implementation "androidx.media3:media3-exoplayer:$media3_version" implementation("com.google.guava:failureaccess:$failureaccess_version")
implementation("com.google.guava:guava:$guava_version")
implementation("androidx.media3:media3-common:$media3_version") {
exclude group: 'com.google.guava', module: 'guava'
exclude group: 'com.google.guava', module: 'failureaccess'
}
implementation("androidx.media3:media3-exoplayer:$media3_version")
// For HLS playback support with ExoPlayer // For HLS playback support with ExoPlayer
implementation "androidx.media3:media3-exoplayer-hls:$media3_version" implementation "androidx.media3:media3-exoplayer-hls:$media3_version"
@@ -114,12 +125,17 @@ dependencies {
def retrofit2_version = "2.6.4" def retrofit2_version = "2.6.4"
implementation 'com.google.protobuf:protobuf-kotlin:3.25.1' implementation 'com.google.protobuf:protobuf-kotlin:3.25.1'
implementation "com.squareup.retrofit2:converter-gson:$retrofit2_version" // Gson 2.10.1 and older: API level 19
implementation("com.google.code.gson:gson:$gson_version")
implementation("com.squareup.retrofit2:converter-gson:$retrofit2_version") {
exclude group: 'com.google.code.gson', module: 'gson'
}
implementation "com.squareup.retrofit2:converter-protobuf:$retrofit2_version" implementation "com.squareup.retrofit2:converter-protobuf:$retrofit2_version"
implementation "com.squareup.retrofit2:retrofit:$retrofit2_version" implementation "com.squareup.retrofit2:retrofit:$retrofit2_version"
implementation 'com.github.bumptech.glide:glide:4.11.0' implementation 'com.github.bumptech.glide:glide:4.11.0'
implementation("androidx.work:work-runtime-ktx:2.9.0")
implementation 'androidx.core:core-ktx:1.11.0-beta02' implementation 'androidx.core:core-ktx:1.11.0-beta02'
implementation 'androidx.multidex:multidex:2.0.1' implementation 'androidx.multidex:multidex:2.0.1'
implementation 'androidx.leanback:leanback:1.2.0-alpha02' implementation 'androidx.leanback:leanback:1.2.0-alpha02'
@@ -129,9 +145,24 @@ dependencies {
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.2" implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.2"
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.0-RC") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.0-RC")
implementation 'com.google.android.exoplayer:exoplayer-ui:2.13.3'
implementation 'com.google.android.exoplayer:exoplayer-core:2.13.3'
implementation 'com.google.android.exoplayer:exoplayer-hls:2.13.3'
implementation 'javax.annotation:javax.annotation-api:1.3.2' implementation 'javax.annotation:javax.annotation-api:1.3.2'
}
configurations.configureEach {
resolutionStrategy {
force("com.google.code.gson:gson:$gson_version")
force "com.google.guava:failureaccess:$failureaccess_version"
force "com.google.guava:guava:$guava_version"
eachDependency { details ->
if (details.requested.group == 'com.google.code.gson') {
details.useVersion "$gson_version"
}
if (details.requested.group == 'com.google.guava' && details.requested.name == 'failureaccess') {
details.useVersion "$failureaccess_version"
}
if (details.requested.group == 'com.google.guava' && details.requested.name == 'guava') {
details.useVersion "$guava_version"
}
}
}
} }
+7 -1
View File
@@ -18,4 +18,10 @@
# If you keep the line number information, uncomment this to # If you keep the line number information, uncomment this to
# hide the original source file name. # hide the original source file name.
#-renamesourcefileattribute SourceFile #-renamesourcefileattribute SourceFile
-keep class com.google.gson.** { *; }
-dontwarn com.google.gson.**
-keep class com.google.guava.** { *; }
-dontwarn com.google.guava.**
+2 -1
View File
@@ -10,12 +10,13 @@
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" /> <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<application <application
android:name=".MyTvApplication" android:name=".MyTVApplication"
android:allowBackup="true" android:allowBackup="true"
android:banner="@drawable/banner" android:banner="@drawable/banner"
android:icon="@drawable/logo" android:icon="@drawable/logo"
Binary file not shown.
Binary file not shown.
+9
View File
@@ -0,0 +1,9 @@
#ifndef AES_H
#define AES_H
#include <stddef.h>
void init();
void encode(const char *in, size_t size, char *out);
#endif
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
@@ -34,7 +34,7 @@ class CardAdapter(
val inflater = LayoutInflater.from(parent.context) val inflater = LayoutInflater.from(parent.context)
val binding = CardBinding.inflate(inflater, parent, false) val binding = CardBinding.inflate(inflater, parent, false)
val application = mainFragment.requireActivity().applicationContext as MyTvApplication val application = mainFragment.requireActivity().applicationContext as MyTVApplication
binding.card.layoutParams.width = application.px2Px(binding.card.layoutParams.width) binding.card.layoutParams.width = application.px2Px(binding.card.layoutParams.width)
binding.card.layoutParams.height = application.px2Px(binding.card.layoutParams.height) binding.card.layoutParams.height = application.px2Px(binding.card.layoutParams.height)
@@ -28,7 +28,7 @@ class ChannelFragment : Fragment() {
_binding = ChannelBinding.inflate(inflater, container, false) _binding = ChannelBinding.inflate(inflater, container, false)
_binding!!.root.visibility = View.GONE _binding!!.root.visibility = View.GONE
val application = requireActivity().applicationContext as MyTvApplication val application = requireActivity().applicationContext as MyTVApplication
binding.channel.layoutParams.width = application.px2Px(binding.channel.layoutParams.width) binding.channel.layoutParams.width = application.px2Px(binding.channel.layoutParams.width)
binding.channel.layoutParams.height = application.px2Px(binding.channel.layoutParams.height) binding.channel.layoutParams.height = application.px2Px(binding.channel.layoutParams.height)
@@ -3,13 +3,37 @@ package com.lizongying.mytv
import android.app.AlertDialog import android.app.AlertDialog
import android.app.Dialog import android.app.Dialog
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import com.lizongying.mytv.databinding.ConfirmationBinding
class ConfirmationFragment( class ConfirmationFragment(
private val listener: ConfirmationListener, private val listener: ConfirmationListener,
private val message: String, private val message: String,
private val update: Boolean private val update: Boolean
) : DialogFragment() { ) : DialogFragment() {
//
// private var _binding: ConfirmationBinding? = null
// private val binding get() = _binding!!
//
// override fun onCreateView(
// inflater: LayoutInflater, container: ViewGroup?,
// savedInstanceState: Bundle?
// ): View {
// _binding = ConfirmationBinding.inflate(inflater, container, false)
// return binding.root
// }
//
// fun updateProgress(progress: Int) {
// binding.progressBar.progress = progress
// }
//
// override fun onDestroyView() {
// super.onDestroyView()
// _binding = null
// }
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
return activity?.let { return activity?.let {
@@ -19,7 +19,7 @@ class ErrorFragment : Fragment() {
): View { ): View {
_binding = ErrorBinding.inflate(inflater, container, false) _binding = ErrorBinding.inflate(inflater, container, false)
val application = requireActivity().applicationContext as MyTvApplication val application = requireActivity().applicationContext as MyTVApplication
binding.logo.layoutParams.width = application.px2Px(binding.logo.layoutParams.width) binding.logo.layoutParams.width = application.px2Px(binding.logo.layoutParams.width)
binding.logo.layoutParams.height = application.px2Px(binding.logo.layoutParams.height) binding.logo.layoutParams.height = application.px2Px(binding.logo.layoutParams.height)
@@ -29,7 +29,7 @@ class InfoFragment : Fragment() {
): View { ): View {
_binding = InfoBinding.inflate(inflater, container, false) _binding = InfoBinding.inflate(inflater, container, false)
val application = requireActivity().applicationContext as MyTvApplication val application = requireActivity().applicationContext as MyTVApplication
binding.info.layoutParams.width = application.px2Px(binding.info.layoutParams.width) binding.info.layoutParams.width = application.px2Px(binding.info.layoutParams.width)
binding.info.layoutParams.height = application.px2Px(binding.info.layoutParams.height) binding.info.layoutParams.height = application.px2Px(binding.info.layoutParams.height)
@@ -7,10 +7,10 @@ import androidx.recyclerview.widget.RecyclerView
class ItemDecoration(context: Context) : RecyclerView.ItemDecoration() { class ItemDecoration(context: Context) : RecyclerView.ItemDecoration() {
private var application: MyTvApplication private var application: MyTVApplication
init { init {
application = context.applicationContext as MyTvApplication application = context.applicationContext as MyTVApplication
} }
override fun getItemOffsets( override fun getItemOffsets(
@@ -17,7 +17,7 @@ class LoadingFragment : Fragment() {
): View { ): View {
_binding = LoadingBinding.inflate(inflater, container, false) _binding = LoadingBinding.inflate(inflater, container, false)
val application = requireActivity().applicationContext as MyTvApplication val application = requireActivity().applicationContext as MyTVApplication
binding.bar.layoutParams.width = application.px2Px(binding.bar.layoutParams.width) binding.bar.layoutParams.width = application.px2Px(binding.bar.layoutParams.width)
binding.bar.layoutParams.height = application.px2Px(binding.bar.layoutParams.height) binding.bar.layoutParams.height = application.px2Px(binding.bar.layoutParams.height)
@@ -8,6 +8,7 @@ import android.util.Log
import android.view.GestureDetector import android.view.GestureDetector
import android.view.KeyEvent import android.view.KeyEvent
import android.view.MotionEvent import android.view.MotionEvent
import android.view.View
import android.view.View.SYSTEM_UI_FLAG_FULLSCREEN import android.view.View.SYSTEM_UI_FLAG_FULLSCREEN
import android.view.View.SYSTEM_UI_FLAG_HIDE_NAVIGATION import android.view.View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
import android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN import android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
@@ -44,13 +45,13 @@ class MainActivity : FragmentActivity(), Request.RequestListener, OnSharedPrefer
private val handler = Handler() private val handler = Handler()
private val delayHideMain: Long = 10000 private val delayHideMain: Long = 10000
private val delayHideSetting: Long = 10000 private val delayHideSetting: Long = 15000
init { init {
Utils.setRequestListener(this) Utils.setRequestListener(this)
} }
private fun syncTime() { fun syncTime() {
lifecycleScope.launch(Dispatchers.IO) { lifecycleScope.launch(Dispatchers.IO) {
val utilsJob = async(start = CoroutineStart.LAZY) { Utils.init() } val utilsJob = async(start = CoroutineStart.LAZY) { Utils.init() }
utilsJob.start() utilsJob.start()
@@ -59,9 +60,6 @@ class MainActivity : FragmentActivity(), Request.RequestListener, OnSharedPrefer
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
Request.setRequestListener(this)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
val lp = window.attributes val lp = window.attributes
@@ -70,6 +68,17 @@ class MainActivity : FragmentActivity(), Request.RequestListener, OnSharedPrefer
window.setAttributes(lp) window.setAttributes(lp)
} }
window.decorView.apply {
systemUiVisibility =
SYSTEM_UI_FLAG_FULLSCREEN or
SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or
View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
SYSTEM_UI_FLAG_HIDE_NAVIGATION or
SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or
View.SYSTEM_UI_FLAG_IMMERSIVE
}
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN) window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
window.decorView.systemUiVisibility = window.decorView.systemUiVisibility =
@@ -82,6 +91,10 @@ class MainActivity : FragmentActivity(), Request.RequestListener, OnSharedPrefer
// window.navigationBarColor = Color.TRANSPARENT // window.navigationBarColor = Color.TRANSPARENT
// } // }
setContentView(R.layout.activity_main)
Request.setRequestListener(this)
if (savedInstanceState == null) { if (savedInstanceState == null) {
val transaction = supportFragmentManager.beginTransaction() val transaction = supportFragmentManager.beginTransaction()
.add(R.id.main_browse_fragment, playerFragment) .add(R.id.main_browse_fragment, playerFragment)
@@ -42,7 +42,7 @@ class MainFragment : Fragment(), CardAdapter.ItemListener {
private var lastVideoUrl = "" private var lastVideoUrl = ""
private lateinit var application: MyTvApplication private lateinit var application: MyTVApplication
private lateinit var gestureDetector: GestureDetector private lateinit var gestureDetector: GestureDetector
@@ -53,7 +53,7 @@ class MainFragment : Fragment(), CardAdapter.ItemListener {
val context = requireContext() val context = requireContext()
_binding = MenuBinding.inflate(inflater, container, false) _binding = MenuBinding.inflate(inflater, container, false)
application = requireActivity().applicationContext as MyTvApplication application = requireActivity().applicationContext as MyTVApplication
binding.menu.layoutParams.width = application.shouldWidthPx() binding.menu.layoutParams.width = application.shouldWidthPx()
binding.menu.layoutParams.height = application.shouldHeightPx() binding.menu.layoutParams.height = application.shouldHeightPx()
@@ -5,10 +5,13 @@ import android.content.Context
import android.content.res.Resources import android.content.res.Resources
import android.util.DisplayMetrics import android.util.DisplayMetrics
import android.view.WindowManager import android.view.WindowManager
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelStore
import androidx.multidex.MultiDex import androidx.multidex.MultiDex
import com.lizongying.mytv.models.MyViewModel
class MyTvApplication : Application() { class MyTVApplication : Application() {
private lateinit var displayMetrics: DisplayMetrics private lateinit var displayMetrics: DisplayMetrics
private lateinit var realDisplayMetrics: DisplayMetrics private lateinit var realDisplayMetrics: DisplayMetrics
@@ -23,6 +26,8 @@ class MyTvApplication : Application() {
private var density = 2.0f private var density = 2.0f
private var scale = 1.0f private var scale = 1.0f
lateinit var myViewModel: MyViewModel
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
@@ -60,6 +65,11 @@ class MyTvApplication : Application() {
deviation = width - Resources.getSystem().displayMetrics.widthPixels deviation = width - Resources.getSystem().displayMetrics.widthPixels
scale = Resources.getSystem().displayMetrics.scaledDensity scale = Resources.getSystem().displayMetrics.scaledDensity
myViewModel = ViewModelProvider(
ViewModelStore(),
ViewModelProvider.NewInstanceFactory()
)[MyViewModel::class.java]
} }
fun getDisplayMetrics(): DisplayMetrics { fun getDisplayMetrics(): DisplayMetrics {
@@ -3,8 +3,6 @@ package com.lizongying.mytv
import android.os.Bundle import android.os.Bundle
import android.util.Log import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.SurfaceHolder
import android.view.SurfaceView
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.ViewTreeObserver import android.view.ViewTreeObserver
@@ -15,41 +13,26 @@ import androidx.media3.common.PlaybackException
import androidx.media3.common.Player import androidx.media3.common.Player
import androidx.media3.common.VideoSize import androidx.media3.common.VideoSize
import androidx.media3.common.util.UnstableApi import androidx.media3.common.util.UnstableApi
import androidx.media3.exoplayer.DefaultRenderersFactory
import androidx.media3.exoplayer.ExoPlayer import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.ui.PlayerView import androidx.media3.ui.PlayerView
import com.google.android.exoplayer2.SimpleExoPlayer
import com.lizongying.mytv.databinding.PlayerBinding import com.lizongying.mytv.databinding.PlayerBinding
import com.lizongying.mytv.models.TVViewModel import com.lizongying.mytv.models.TVViewModel
class PlayerFragment : Fragment(), SurfaceHolder.Callback { class PlayerFragment : Fragment() {
private var _binding: PlayerBinding? = null private var _binding: PlayerBinding? = null
private var playerView: PlayerView? = null private var playerView: PlayerView? = null
private var tvViewModel: TVViewModel? = null private var tvViewModel: TVViewModel? = null
private val aspectRatio = 16f / 9f private val aspectRatio = 16f / 9f
private lateinit var surfaceView: SurfaceView
private lateinit var surfaceHolder: SurfaceHolder
private var exoPlayer: SimpleExoPlayer? = null
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?
): View { ): View {
_binding = PlayerBinding.inflate(inflater, container, false) _binding = PlayerBinding.inflate(inflater, container, false)
if (Utils.isTmallDevice()) { playerView = _binding!!.playerView
_binding!!.playerView.visibility = View.GONE
surfaceView = _binding!!.surfaceView
surfaceHolder = surfaceView.holder
surfaceHolder.addCallback(this)
} else {
_binding!!.surfaceView.visibility = View.GONE
playerView = _binding!!.playerView
}
playerView?.viewTreeObserver?.addOnGlobalLayoutListener(object : playerView?.viewTreeObserver?.addOnGlobalLayoutListener(object :
ViewTreeObserver.OnGlobalLayoutListener { ViewTreeObserver.OnGlobalLayoutListener {
@@ -110,10 +93,7 @@ class PlayerFragment : Fragment(), SurfaceHolder.Callback {
playerView?.player?.run { playerView?.player?.run {
setMediaItem(MediaItem.fromUri(tvViewModel.getVideoUrlCurrent())) setMediaItem(MediaItem.fromUri(tvViewModel.getVideoUrlCurrent()))
prepare() prepare()
} volume = tvViewModel.getTV().volume
exoPlayer?.run {
setMediaItem(com.google.android.exoplayer2.MediaItem.fromUri(tvViewModel.getVideoUrlCurrent()))
prepare()
} }
} }
@@ -125,11 +105,6 @@ class PlayerFragment : Fragment(), SurfaceHolder.Callback {
playerView!!.player?.prepare() playerView!!.player?.prepare()
playerView!!.player?.play() playerView!!.player?.play()
} }
if (exoPlayer?.isPlaying == false) {
Log.i(TAG, "replay")
exoPlayer?.prepare()
exoPlayer?.play()
}
} }
override fun onResume() { override fun onResume() {
@@ -142,9 +117,6 @@ class PlayerFragment : Fragment(), SurfaceHolder.Callback {
if (playerView != null && playerView!!.player?.isPlaying == true) { if (playerView != null && playerView!!.player?.isPlaying == true) {
playerView!!.player?.stop() playerView!!.player?.stop()
} }
if (exoPlayer?.isPlaying == true) {
exoPlayer?.stop()
}
} }
override fun onDestroy() { override fun onDestroy() {
@@ -152,7 +124,6 @@ class PlayerFragment : Fragment(), SurfaceHolder.Callback {
if (playerView != null) { if (playerView != null) {
playerView!!.player?.release() playerView!!.player?.release()
} }
exoPlayer?.release()
} }
override fun onDestroyView() { override fun onDestroyView() {
@@ -163,16 +134,4 @@ class PlayerFragment : Fragment(), SurfaceHolder.Callback {
companion object { companion object {
private const val TAG = "PlayerFragment" private const val TAG = "PlayerFragment"
} }
override fun surfaceCreated(holder: SurfaceHolder) {
exoPlayer = SimpleExoPlayer.Builder(requireContext()).build()
exoPlayer?.setVideoSurfaceHolder(surfaceHolder)
exoPlayer?.playWhenReady = true
}
override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
}
override fun surfaceDestroyed(holder: SurfaceHolder) {
}
} }
@@ -6,14 +6,18 @@ import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.View.GONE
import android.view.View.VISIBLE
import android.view.ViewGroup import android.view.ViewGroup
import android.view.WindowManager import android.view.WindowManager
import android.widget.Toast import android.widget.Toast
import androidx.core.app.ActivityCompat import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import androidx.core.view.marginEnd import androidx.core.view.marginEnd
import androidx.core.view.marginTop import androidx.core.view.marginTop
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import com.lizongying.mytv.api.YSP
import com.lizongying.mytv.databinding.SettingBinding import com.lizongying.mytv.databinding.SettingBinding
@@ -97,7 +101,14 @@ class SettingFragment : DialogFragment() {
requestInstallPermissions() requestInstallPermissions()
} }
val application = requireActivity().applicationContext as MyTvApplication binding.clear.setOnClickListener {
(requireActivity() as MainActivity).syncTime()
SP.guid = ""
YSP.getGuid()
}
val application = requireActivity().applicationContext as MyTVApplication
val textSize = application.px2PxFont(binding.switchChannelReversal.textSize)
binding.content.layoutParams.width = binding.content.layoutParams.width =
application.px2Px(binding.content.layoutParams.width) application.px2Px(binding.content.layoutParams.width)
@@ -108,51 +119,41 @@ class SettingFragment : DialogFragment() {
application.px2Px(binding.content.paddingBottom) application.px2Px(binding.content.paddingBottom)
) )
binding.name.textSize = application.px2PxFont(binding.name.textSize) binding.name.textSize = application.px2PxFont(binding.name.textSize)
binding.version.textSize = application.px2PxFont(binding.version.textSize) binding.version.textSize = textSize
val layoutParamsVersion = binding.version.layoutParams as ViewGroup.MarginLayoutParams val layoutParamsVersion = binding.version.layoutParams as ViewGroup.MarginLayoutParams
layoutParamsVersion.topMargin = application.px2Px(binding.version.marginTop) layoutParamsVersion.topMargin = application.px2Px(binding.version.marginTop)
binding.version.layoutParams = layoutParamsVersion binding.version.layoutParams = layoutParamsVersion
binding.checkVersion.textSize = application.px2PxFont(binding.checkVersion.textSize) binding.checkVersion.textSize = textSize
val layoutParamsCheckVersion = val layoutParamsCheckVersion =
binding.checkVersion.layoutParams as ViewGroup.MarginLayoutParams binding.checkVersion.layoutParams as ViewGroup.MarginLayoutParams
layoutParamsCheckVersion.marginEnd = application.px2Px(binding.checkVersion.marginEnd) layoutParamsCheckVersion.marginEnd = application.px2Px(binding.checkVersion.marginEnd)
binding.checkVersion.layoutParams = layoutParamsCheckVersion binding.checkVersion.layoutParams = layoutParamsCheckVersion
binding.versionName.textSize = application.px2PxFont(binding.versionName.textSize) binding.versionName.textSize = textSize
binding.exit.textSize = application.px2PxFont(binding.exit.textSize) binding.clear.textSize = textSize
binding.exit.textSize = textSize
binding.switchChannelReversal.textSize = val layoutParamsChannelSwitch =
application.px2PxFont(binding.switchChannelReversal.textSize)
val layoutParamsChannelReversal =
binding.switchChannelReversal.layoutParams as ViewGroup.MarginLayoutParams binding.switchChannelReversal.layoutParams as ViewGroup.MarginLayoutParams
layoutParamsChannelReversal.topMargin = layoutParamsChannelSwitch.topMargin =
application.px2Px(binding.switchChannelReversal.marginTop) application.px2Px(binding.switchChannelReversal.marginTop)
binding.switchChannelReversal.layoutParams = layoutParamsChannelReversal
binding.switchChannelNum.textSize = application.px2PxFont(binding.switchChannelNum.textSize) binding.switchChannelReversal.textSize = textSize
val layoutParamsChannelNum = binding.switchChannelReversal.layoutParams = layoutParamsChannelSwitch
binding.switchChannelNum.layoutParams as ViewGroup.MarginLayoutParams
layoutParamsChannelNum.topMargin = application.px2Px(binding.switchChannelNum.marginTop)
binding.switchChannelNum.layoutParams = layoutParamsChannelNum
binding.switchTime.textSize = application.px2PxFont(binding.switchTime.textSize) binding.switchChannelNum.textSize = textSize
val layoutParamsTime = binding.switchTime.layoutParams as ViewGroup.MarginLayoutParams binding.switchChannelNum.layoutParams = layoutParamsChannelSwitch
layoutParamsTime.topMargin = application.px2Px(binding.switchTime.marginTop)
binding.switchTime.layoutParams = layoutParamsTime
binding.switchBootStartup.textSize = binding.switchTime.textSize = textSize
application.px2PxFont(binding.switchBootStartup.textSize) binding.switchTime.layoutParams = layoutParamsChannelSwitch
val layoutParamsBootStartup =
binding.switchBootStartup.layoutParams as ViewGroup.MarginLayoutParams
layoutParamsBootStartup.topMargin = application.px2Px(binding.switchBootStartup.marginTop)
binding.switchBootStartup.layoutParams = layoutParamsBootStartup
binding.switchGrid.textSize = application.px2PxFont(binding.switchGrid.textSize) binding.switchBootStartup.textSize = textSize
val layoutParamsGrid = binding.switchGrid.layoutParams as ViewGroup.MarginLayoutParams binding.switchBootStartup.layoutParams = layoutParamsChannelSwitch
layoutParamsGrid.topMargin = application.px2Px(binding.switchGrid.marginTop)
binding.switchGrid.layoutParams = layoutParamsGrid binding.switchGrid.textSize = textSize
binding.switchGrid.layoutParams = layoutParamsChannelSwitch
binding.appreciate.layoutParams.width = binding.appreciate.layoutParams.width =
application.px2Px(binding.appreciate.layoutParams.width) application.px2Px(binding.appreciate.layoutParams.width)
@@ -161,6 +162,21 @@ class SettingFragment : DialogFragment() {
requireActivity().finishAffinity() requireActivity().finishAffinity()
} }
// val myViewModel = application.myViewModel
// application.myViewModel.downloadProgress.observe(viewLifecycleOwner) { _ ->
// val downloadProgress = myViewModel.downloadProgress.value
// if (downloadProgress != null) {
// if (downloadProgress == 100) {
// binding.progressBar.visibility = GONE
// } else {
// if (!binding.progressBar.isVisible) {
// binding.progressBar.visibility = VISIBLE
// }
// binding.progressBar.progress = downloadProgress
// }
// }
// }
updateManager = UpdateManager(context, context.appVersionCode) updateManager = UpdateManager(context, context.appVersionCode)
return binding.root return binding.root
@@ -24,7 +24,7 @@ class TimeFragment : Fragment() {
): View { ): View {
_binding = TimeBinding.inflate(inflater, container, false) _binding = TimeBinding.inflate(inflater, container, false)
val application = requireActivity().applicationContext as MyTvApplication val application = requireActivity().applicationContext as MyTVApplication
binding.time.layoutParams.width = application.px2Px(binding.time.layoutParams.width) binding.time.layoutParams.width = application.px2Px(binding.time.layoutParams.width)
binding.time.layoutParams.height = application.px2Px(binding.time.layoutParams.height) binding.time.layoutParams.height = application.px2Px(binding.time.layoutParams.height)
@@ -1,26 +1,17 @@
package com.lizongying.mytv package com.lizongying.mytv
import android.app.DownloadManager
import android.app.DownloadManager.Request
import android.content.BroadcastReceiver
import android.content.Context 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.util.Log
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkManager
import androidx.work.workDataOf
import com.lizongying.mytv.api.ApiClient import com.lizongying.mytv.api.ApiClient
import com.lizongying.mytv.requests.ReleaseRequest import com.lizongying.mytv.requests.ReleaseRequest
import com.lizongying.mytv.requests.ReleaseResponse import com.lizongying.mytv.requests.ReleaseResponse
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.io.File
class UpdateManager( class UpdateManager(
@@ -32,17 +23,15 @@ class UpdateManager(
private var releaseRequest = ReleaseRequest() private var releaseRequest = ReleaseRequest()
private var release: ReleaseResponse? = null private var release: ReleaseResponse? = null
private var downloadReceiver: DownloadReceiver? = null
fun checkAndUpdate() { fun checkAndUpdate() {
CoroutineScope(Dispatchers.Main).launch { CoroutineScope(Dispatchers.Main).launch {
var text = "版本获取失败" var text = "版本获取失败"
var update = false var update = false
try { try {
release = releaseRequest.getRelease() release = releaseRequest.getRelease()
Log.i(TAG, "versionCode $versionCode ${release?.version_code}") val code = release?.version_code
if (release?.version_code != null) { if (code != null) {
if (release?.version_code!! > versionCode) { if (code.toLong() >= versionCode) {
text = "最新版本:${release?.version_name}" text = "最新版本:${release?.version_name}"
update = true update = true
} else { } else {
@@ -61,170 +50,24 @@ class UpdateManager(
dialog.show((context as FragmentActivity).supportFragmentManager, TAG) dialog.show((context as FragmentActivity).supportFragmentManager, TAG)
} }
private fun startDownload(release: ReleaseResponse) { private fun startDownload(context: Context, release: ReleaseResponse) {
val versionName = release.version_name
val apkName = "my-tv" val apkName = "my-tv"
val apkFileName = "$apkName-${release.version_name}.apk" val apkFileName = "$apkName-${release.version_name}.apk"
val downloadManager = val downloadUrl =
context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager "${ApiClient.DOWNLOAD_HOST}${release.version_name}/$apkName-${release.version_name}.apk"
val request = Log.i(TAG, "downloadUrl: $downloadUrl")
Request(Uri.parse("${ApiClient.DOWNLOAD_HOST}${release.version_name}/$apkName-${release.version_name}.apk")) val downloadRequest = OneTimeWorkRequestBuilder<UpdateWorker>()
Log.i( .setInputData(
TAG, workDataOf(
"url ${Uri.parse("${ApiClient.DOWNLOAD_HOST}${release.version_name}/$apkName-${release.version_name}.apk")}" "VERSION_NAME" to versionName,
) "APK_FILENAME" to apkFileName,
context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)?.mkdirs() "DOWNLOAD_URL" to downloadUrl
Log.i(TAG, "save dir ${Environment.DIRECTORY_DOWNLOADS}") )
request.setDestinationInExternalFilesDir(
context,
Environment.DIRECTORY_DOWNLOADS,
apkFileName
)
request.setTitle("${context.resources.getString(R.string.app_name)} ${release.version_name}")
request.setNotificationVisibility(Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
request.setAllowedOverRoaming(false)
request.setMimeType("application/vnd.android.package-archive")
// 获取下载任务的引用
val downloadReference = downloadManager.enqueue(request)
downloadReceiver = DownloadReceiver(context, apkFileName, downloadReference)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.registerReceiver(
downloadReceiver,
IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE),
Context.RECEIVER_NOT_EXPORTED,
) )
} else { .build()
context.registerReceiver(
downloadReceiver,
IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE)
)
}
getDownloadProgress(context, downloadReference) { progress -> WorkManager.getInstance(context).enqueue(downloadRequest)
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(
private val context: Context,
private val apkFileName: String,
private val downloadReference: Long
) : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val reference = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1)
Log.i(TAG, "reference $reference")
if (reference == downloadReference) {
val downloadManager =
context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
val query = DownloadManager.Query().setFilterById(downloadReference)
val cursor = downloadManager.query(query)
if (cursor != null && cursor.moveToFirst()) {
val statusIndex = cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)
if (statusIndex < 0) {
Log.i(TAG, "Download failure")
return
}
val status = cursor.getInt(statusIndex)
val progressIndex =
cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR)
if (progressIndex < 0) {
Log.i(TAG, "Download failure")
return
}
val progress = cursor.getInt(progressIndex)
val totalSizeIndex =
cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES)
val totalSize = cursor.getInt(totalSizeIndex)
cursor.close()
when (status) {
DownloadManager.STATUS_SUCCESSFUL -> {
installNewVersion()
}
DownloadManager.STATUS_FAILED -> {
// Handle download failure
Log.i(TAG, "Download failure")
}
else -> {
// Update UI with download progress
val percentage = progress * 100 / totalSize
Log.i(TAG, "Download progress: $percentage%")
}
}
}
}
}
private fun installNewVersion() {
val apkFile = File(
context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
apkFileName
)
Log.i(TAG, "apkFile $apkFile")
if (apkFile.exists()) {
val apkUri = Uri.parse("file://$apkFile")
Log.i(TAG, "apkUri $apkUri")
val installIntent = Intent(Intent.ACTION_VIEW).apply {
setDataAndType(apkUri, "application/vnd.android.package-archive")
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_ACTIVITY_NEW_TASK)
}
context.startActivity(installIntent)
} else {
Log.e(TAG, "APK file does not exist!")
}
}
} }
companion object { companion object {
@@ -233,16 +76,9 @@ class UpdateManager(
override fun onConfirm() { override fun onConfirm() {
Log.i(TAG, "onConfirm $release") Log.i(TAG, "onConfirm $release")
release?.let { startDownload(it) } release?.let { startDownload(context, it) }
} }
override fun onCancel() { override fun onCancel() {
} }
fun destroy() {
if (downloadReceiver != null) {
context.unregisterReceiver(downloadReceiver)
Log.i(TAG, "destroy downloadReceiver")
}
}
} }
@@ -0,0 +1,158 @@
package com.lizongying.mytv
import android.app.DownloadManager
import android.app.NotificationChannel
import android.app.NotificationManager
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.util.Log
import androidx.core.app.NotificationCompat
import androidx.core.content.FileProvider
import androidx.work.CoroutineWorker
import androidx.work.WorkerParameters
import com.lizongying.mytv.models.MyViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.io.File
class UpdateWorker(context: Context, params: WorkerParameters) : CoroutineWorker(context, params) {
private lateinit var notificationManager: NotificationManager
private lateinit var notificationBuilder: NotificationCompat.Builder
private lateinit var myViewModel: MyViewModel
override suspend fun doWork(): Result {
val downloadUrl = inputData.getString("DOWNLOAD_URL") ?: return Result.failure()
val apkFileName = inputData.getString("APK_FILENAME") ?: return Result.failure()
val versionName = inputData.getString("VERSION_NAME") ?: return Result.failure()
showNotification(applicationContext)
val app = applicationContext as MyTVApplication
myViewModel = app.myViewModel
return withContext(Dispatchers.IO) {
try {
downloadAndInstall(applicationContext, downloadUrl, apkFileName, versionName)
Result.success()
} catch (e: Exception) {
Result.failure()
}
}
}
private fun showNotification(context: Context) {
notificationManager =
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationBuilder = NotificationCompat.Builder(context, "download_channel").apply {
setSmallIcon(android.R.drawable.stat_sys_download)
setContentTitle("Downloading Update")
setContentText("Download in progress")
priority = NotificationCompat.PRIORITY_LOW
setOngoing(true)
setProgress(100, 0, false)
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(
"download_channel",
"Download Updates",
NotificationManager.IMPORTANCE_LOW
)
notificationManager.createNotificationChannel(channel)
}
notificationManager.notify(1, notificationBuilder.build())
}
private fun downloadAndInstall(
context: Context,
downloadUrl: String,
apkFileName: String,
versionName: String
) {
context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)?.mkdirs()
Log.i(TAG, "save dir ${Environment.DIRECTORY_DOWNLOADS}")
val request = DownloadManager.Request(Uri.parse(downloadUrl)).apply {
setTitle("${context.resources.getString(R.string.app_name)} $versionName Downloading")
setDescription("Downloading the latest version of the app")
setDestinationInExternalFilesDir(context, Environment.DIRECTORY_DOWNLOADS, apkFileName)
setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
// setAllowedOverRoaming(false)
setMimeType("application/vnd.android.package-archive")
}
val manager = context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
val downloadId = manager.enqueue(request)
var downloading = true
while (downloading) {
val query = DownloadManager.Query().setFilterById(downloadId)
val cursor = manager.query(query)
if (cursor.moveToFirst()) {
val bytesDownloaded =
cursor.getInt(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR))
val bytesTotal =
cursor.getInt(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_TOTAL_SIZE_BYTES))
if (bytesTotal > 0) {
val progress = (bytesDownloaded * 100L / bytesTotal).toInt()
Log.i(TAG, "progress $progress")
// myViewModel.setDownloadProgress(progress)
notificationBuilder.setProgress(100, progress, false)
notificationManager.notify(1, notificationBuilder.build())
}
when (cursor.getInt(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_STATUS))) {
DownloadManager.STATUS_SUCCESSFUL -> downloading = false
DownloadManager.STATUS_FAILED -> {
downloading = false
throw Exception("Download failed")
}
}
}
cursor.close()
}
notificationBuilder.setContentText("Download complete")
.setProgress(0, 0, false)
.setOngoing(false)
notificationManager.notify(1, notificationBuilder.build())
val apkFile = File(
context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),
apkFileName
)
if (apkFile.exists()) {
val apkUri: Uri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
FileProvider.getUriForFile(context, context.packageName + ".fileprovider", apkFile)
.apply {
Intent.FLAG_GRANT_READ_URI_PERMISSION
}
} else {
Uri.parse("file://${apkFile.absolutePath}")
// Uri.fromFile(apkFile)
}
// val apkUri = Uri.parse("file://$apkFile")
Log.i(TAG, "apkUri $apkUri")
val installIntent = Intent(Intent.ACTION_VIEW).apply {
setDataAndType(apkUri, "application/vnd.android.package-archive")
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_ACTIVITY_NEW_TASK)
}
context.startActivity(installIntent)
} else {
Log.e(TAG, "APK file does not exist!")
}
}
companion object {
private const val TAG = "UpdateWorker"
}
}
@@ -3,6 +3,7 @@ package com.lizongying.mytv.api
import android.os.Build import android.os.Build
import android.util.Log import android.util.Log
import com.google.gson.Gson
import com.lizongying.mytv.jce.JceConverterFactory import com.lizongying.mytv.jce.JceConverterFactory
import com.lizongying.mytv.requests.ReleaseService import com.lizongying.mytv.requests.ReleaseService
import okhttp3.ConnectionSpec import okhttp3.ConnectionSpec
@@ -30,12 +31,13 @@ class ApiClient {
private val fUrl = "https://m.fengshows.com/" private val fUrl = "https://m.fengshows.com/"
private var okHttpClient = getUnsafeOkHttpClient() private var okHttpClient = getUnsafeOkHttpClient()
private var gson = Gson()
val yspApiService: YSPApiService by lazy { val yspApiService: YSPApiService by lazy {
Retrofit.Builder() Retrofit.Builder()
.baseUrl(yspUrl) .baseUrl(yspUrl)
.client(okHttpClient) .client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create()) .addConverterFactory(GsonConverterFactory.create(gson))
.build().create(YSPApiService::class.java) .build().create(YSPApiService::class.java)
} }
@@ -43,7 +45,7 @@ class ApiClient {
Retrofit.Builder() Retrofit.Builder()
.baseUrl(myUrl) .baseUrl(myUrl)
.client(okHttpClient) .client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create()) .addConverterFactory(GsonConverterFactory.create(gson))
.build().create(YSPTokenService::class.java) .build().create(YSPTokenService::class.java)
} }
@@ -51,7 +53,7 @@ class ApiClient {
Retrofit.Builder() Retrofit.Builder()
.baseUrl(HOST) .baseUrl(HOST)
.client(okHttpClient) .client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create()) .addConverterFactory(GsonConverterFactory.create(gson))
.build().create(ReleaseService::class.java) .build().create(ReleaseService::class.java)
} }
@@ -67,7 +69,7 @@ class ApiClient {
Retrofit.Builder() Retrofit.Builder()
.baseUrl(traceUrl) .baseUrl(traceUrl)
.client(okHttpClient) .client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create()) .addConverterFactory(GsonConverterFactory.create(gson))
.build().create(YSPBtraceService::class.java) .build().create(YSPBtraceService::class.java)
} }
@@ -75,7 +77,7 @@ class ApiClient {
Retrofit.Builder() Retrofit.Builder()
.baseUrl(trace2Url) .baseUrl(trace2Url)
.client(okHttpClient) .client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create()) .addConverterFactory(GsonConverterFactory.create(gson))
.build().create(YSPBtraceService::class.java) .build().create(YSPBtraceService::class.java)
} }
@@ -83,7 +85,7 @@ class ApiClient {
Retrofit.Builder() Retrofit.Builder()
.baseUrl(tokenUrl) .baseUrl(tokenUrl)
.client(okHttpClient) .client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create()) .addConverterFactory(GsonConverterFactory.create(gson))
.build().create(YSPApiService::class.java) .build().create(YSPApiService::class.java)
} }
@@ -91,7 +93,7 @@ class ApiClient {
Retrofit.Builder() Retrofit.Builder()
.baseUrl(trace3Url) .baseUrl(trace3Url)
.client(okHttpClient) .client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create()) .addConverterFactory(GsonConverterFactory.create(gson))
.build().create(YSPBtraceService::class.java) .build().create(YSPBtraceService::class.java)
} }
@@ -107,7 +109,7 @@ class ApiClient {
Retrofit.Builder() Retrofit.Builder()
.baseUrl(fUrl) .baseUrl(fUrl)
.client(okHttpClient) .client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create()) .addConverterFactory(GsonConverterFactory.create(gson))
.build().create(FAuthService::class.java) .build().create(FAuthService::class.java)
} }
@@ -166,7 +168,7 @@ class ApiClient {
val sslContext = SSLContext.getInstance("SSL") val sslContext = SSLContext.getInstance("SSL")
sslContext.init(null, trustAllCerts, java.security.SecureRandom()) 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() val builder = OkHttpClient.Builder()
.sslSocketFactory(sslContext.socketFactory, trustAllCerts[0] as X509TrustManager) .sslSocketFactory(sslContext.socketFactory, trustAllCerts[0] as X509TrustManager)
@@ -7,6 +7,8 @@ class Encryptor {
external fun encrypt(t: String, e: String, r: String, n: String, i: String): String external fun encrypt(t: String, e: String, r: String, n: String, i: String): String
external fun encrypt2(t: String): String
external fun hash(data: ByteArray): ByteArray? external fun hash(data: ByteArray): ByteArray?
external fun hash2(data: ByteArray): ByteArray? external fun hash2(data: ByteArray): ByteArray?
@@ -58,6 +58,7 @@ object YSP {
var yspsdkinput = "" var yspsdkinput = ""
var openapi_signature = "" var openapi_signature = ""
var yspticket = ""
var nseqId = 1 var nseqId = 1
var nrequest_id = "" var nrequest_id = ""
@@ -86,6 +87,8 @@ object YSP {
encryptor.encrypt(cnlid, timeStr, appVer, guid, platform) encryptor.encrypt(cnlid, timeStr, appVer, guid, platform)
randStr = getRand() randStr = getRand()
signature = getSignature() signature = getSignature()
yspticket = encryptor.encrypt2("$livepid&$timeStr&$guid&519748109").lowercase()
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"}""" 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"}"""
} }
@@ -103,18 +106,18 @@ object YSP {
cKey = cKey =
encryptor.encrypt(cnlid, timeStr, appVer, guid, platform) 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")
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++ nseqId++
nrequest_id = "999999" + getRand() + getTimeStr() nrequest_id = "999999" + getRand() + getTimeStr()
openapi_signature = md("yspappid:519748109;host:www.yangshipin.cn;protocol:https:;token:$token2;input:$yspsdkinput-$guid-$nseqId-$nrequest_id;") openapi_signature =
md("yspappid:519748109;host:www.yangshipin.cn;protocol:https:;token:$token2;input:$yspsdkinput-$guid-$nseqId-$nrequest_id;")
} }
fun md(str:String):String { fun md(str: String): String {
val md = MessageDigest.getInstance("MD5") val md = MessageDigest.getInstance("MD5")
md.update(str.toByteArray()) md.update(str.toByteArray())
val digest = md.digest() val digest = md.digest()
@@ -148,6 +151,7 @@ object YSP {
var guid = SP.guid var guid = SP.guid
if (guid.length < 18) { if (guid.length < 18) {
guid = generateGuid() guid = generateGuid()
this.guid = guid
SP.guid = guid SP.guid = guid
} }
return guid return guid
@@ -22,6 +22,7 @@ interface YSPApiService {
@Header("Yspplayertoken") token: String, @Header("Yspplayertoken") token: String,
@Header("Yspsdkinput") Yspsdkinput: String, @Header("Yspsdkinput") Yspsdkinput: String,
@Header("yspsdksign") yspsdksign: String, @Header("yspsdksign") yspsdksign: String,
@Header("Yspticket") Yspticket: String,
@Header("Seqid") Seqid: String, @Header("Seqid") Seqid: String,
@Header("Request-Id") RequestId: String, @Header("Request-Id") RequestId: String,
@Header("Yspappid") Yspappid: String="519748109", @Header("Yspappid") Yspappid: String="519748109",
@@ -0,0 +1,19 @@
package com.lizongying.mytv.models
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
class MyViewModel : ViewModel() {
private var _downloadProgress = MutableLiveData<Int>()
val downloadProgress: LiveData<Int>
get() = _downloadProgress
fun setDownloadProgress(progress: Int) {
_downloadProgress.value = progress
}
init {
_downloadProgress.value = 0
}
}
@@ -15,6 +15,7 @@ data class TV(
var programType: ProgramType, var programType: ProgramType,
var needToken: Boolean = false, var needToken: Boolean = false,
var mustToken: Boolean = false, var mustToken: Boolean = false,
var volume: Float = 0.1F,
) : Serializable { ) : Serializable {
override fun toString(): String { override fun toString(): String {
@@ -21,7 +21,8 @@ object TVList {
"2022576801", "2022576801",
ProgramType.Y_PROTO, ProgramType.Y_PROTO,
false, false,
mustToken = false mustToken = false,
0.5F
), ),
TV( TV(
0, 0,
@@ -34,7 +35,8 @@ object TVList {
"2022576701", "2022576701",
ProgramType.Y_PROTO, ProgramType.Y_PROTO,
true, true,
mustToken = false mustToken = false,
0.5F
), ),
TV( TV(
0, 0,
@@ -47,7 +49,8 @@ object TVList {
"2022576501", "2022576501",
ProgramType.Y_PROTO, ProgramType.Y_PROTO,
true, true,
mustToken = true mustToken = true,
0.5F
), ),
TV( TV(
0, 0,
@@ -60,7 +63,8 @@ object TVList {
"2022576601", "2022576601",
ProgramType.Y_PROTO, ProgramType.Y_PROTO,
false, false,
mustToken = false mustToken = false,
0.5F
), ),
TV( TV(
0, 0,
@@ -73,7 +77,8 @@ object TVList {
"2022576401", "2022576401",
ProgramType.Y_PROTO, ProgramType.Y_PROTO,
true, true,
mustToken = false mustToken = false,
0.5F
), ),
TV( TV(
0, 0,
@@ -86,7 +91,8 @@ object TVList {
"2013693901", "2013693901",
ProgramType.Y_PROTO, ProgramType.Y_PROTO,
true, true,
mustToken = true mustToken = true,
0.5F
), ),
TV( TV(
0, 0,
@@ -99,7 +105,8 @@ object TVList {
"2022576201", "2022576201",
ProgramType.Y_PROTO, ProgramType.Y_PROTO,
true, true,
mustToken = false mustToken = false,
0.5F
), ),
TV( TV(
0, 0,
@@ -112,7 +119,8 @@ object TVList {
"2022576101", "2022576101",
ProgramType.Y_PROTO, ProgramType.Y_PROTO,
true, true,
mustToken = true mustToken = true,
0.5F
), ),
TV( TV(
0, 0,
@@ -125,7 +133,8 @@ object TVList {
"2022576001", "2022576001",
ProgramType.Y_PROTO, ProgramType.Y_PROTO,
true, true,
mustToken = false mustToken = false,
0.5F
), ),
TV( TV(
0, 0,
@@ -138,7 +147,8 @@ object TVList {
"2022573001", "2022573001",
ProgramType.Y_PROTO, ProgramType.Y_PROTO,
true, true,
mustToken = false mustToken = false,
0.5F
), ),
TV( TV(
0, 0,
@@ -151,7 +161,8 @@ object TVList {
"2022575901", "2022575901",
ProgramType.Y_PROTO, ProgramType.Y_PROTO,
true, true,
mustToken = false mustToken = false,
0.5F
), ),
TV( TV(
0, 0,
@@ -164,7 +175,8 @@ object TVList {
"2022575801", "2022575801",
ProgramType.Y_PROTO, ProgramType.Y_PROTO,
true, true,
mustToken = false mustToken = false,
0.5F
), ),
TV( TV(
0, 0,
@@ -177,7 +189,8 @@ object TVList {
"2022575701", "2022575701",
ProgramType.Y_PROTO, ProgramType.Y_PROTO,
false, false,
mustToken = false mustToken = false,
0.5F
), ),
TV( TV(
0, 0,
@@ -190,7 +203,8 @@ object TVList {
"2022575601", "2022575601",
ProgramType.Y_PROTO, ProgramType.Y_PROTO,
true, true,
mustToken = false mustToken = false,
0.5F
), ),
TV( TV(
0, 0,
@@ -203,7 +217,8 @@ object TVList {
"2022575501", "2022575501",
ProgramType.Y_PROTO, ProgramType.Y_PROTO,
true, true,
mustToken = false mustToken = false,
0.5F
), ),
TV( TV(
0, 0,
@@ -216,7 +231,8 @@ object TVList {
"2022575401", "2022575401",
ProgramType.Y_PROTO, ProgramType.Y_PROTO,
true, true,
mustToken = false mustToken = false,
0.5F
), ),
TV( TV(
0, 0,
@@ -229,7 +245,8 @@ object TVList {
"2022575301", "2022575301",
ProgramType.Y_PROTO, ProgramType.Y_PROTO,
true, true,
mustToken = false mustToken = false,
0.5F
), ),
TV( TV(
0, 0,
@@ -242,7 +259,8 @@ object TVList {
"2022576301", "2022576301",
ProgramType.Y_PROTO, ProgramType.Y_PROTO,
true, true,
mustToken = false mustToken = false,
0.5F
), ),
TV( TV(
0, 0,
@@ -255,7 +273,8 @@ object TVList {
"2022575201", "2022575201",
ProgramType.Y_PROTO, ProgramType.Y_PROTO,
true, true,
mustToken = false mustToken = false,
0.5F
), ),
TV( TV(
0, 0,
@@ -268,7 +287,8 @@ object TVList {
"2020603421", "2020603421",
ProgramType.Y_JCE, ProgramType.Y_JCE,
false, false,
mustToken = false mustToken = false,
0.8F
), ),
TV( TV(
0, 0,
@@ -738,7 +758,8 @@ object TVList {
"2019927403", "2019927403",
ProgramType.Y_JCE, ProgramType.Y_JCE,
true, true,
mustToken = false mustToken = false,
0.5F
), ),
TV( TV(
0, 0,
@@ -751,7 +772,8 @@ object TVList {
"2022606701", "2022606701",
ProgramType.Y_JCE, ProgramType.Y_JCE,
true, true,
mustToken = false mustToken = false,
0.8F
), ),
TV( TV(
0, 0,
@@ -764,7 +786,8 @@ object TVList {
"2022823801", "2022823801",
ProgramType.Y_JCE, ProgramType.Y_JCE,
true, true,
mustToken = false mustToken = false,
0.6F
), ),
), ),
"港澳台" to listOf( "港澳台" to listOf(
@@ -779,7 +802,8 @@ object TVList {
"", "",
ProgramType.F, ProgramType.F,
false, false,
mustToken = false mustToken = false,
0.7F
), ),
TV( TV(
0, 0,
@@ -792,7 +816,8 @@ object TVList {
"", "",
ProgramType.F, ProgramType.F,
false, false,
mustToken = false mustToken = false,
0.7F
), ),
TV( TV(
0, 0,
@@ -805,7 +830,8 @@ object TVList {
"", "",
ProgramType.F, ProgramType.F,
false, false,
mustToken = false mustToken = false,
0.7F
), ),
), ),
"国际" to listOf( "国际" to listOf(
@@ -820,7 +846,8 @@ object TVList {
"2022575001", "2022575001",
ProgramType.Y_PROTO, ProgramType.Y_PROTO,
false, false,
mustToken = false mustToken = false,
0.5F
), ),
TV( TV(
0, 0,
@@ -833,7 +860,8 @@ object TVList {
"2022574901", "2022574901",
ProgramType.Y_PROTO, ProgramType.Y_PROTO,
false, false,
mustToken = false mustToken = false,
0.5F
), ),
TV( TV(
0, 0,
@@ -846,7 +874,8 @@ object TVList {
"2022574801", "2022574801",
ProgramType.Y_PROTO, ProgramType.Y_PROTO,
false, false,
mustToken = false mustToken = false,
0.5F
), ),
TV( TV(
0, 0,
@@ -859,7 +888,8 @@ object TVList {
"2022574601", "2022574601",
ProgramType.Y_PROTO, ProgramType.Y_PROTO,
false, false,
mustToken = false mustToken = false,
0.5F
), ),
TV( TV(
0, 0,
@@ -872,7 +902,8 @@ object TVList {
"2022571701", "2022571701",
ProgramType.Y_PROTO, ProgramType.Y_PROTO,
false, false,
mustToken = false mustToken = false,
0.5F
), ),
TV( TV(
0, 0,
@@ -885,13 +916,14 @@ object TVList {
"2022574701", "2022574701",
ProgramType.Y_PROTO, ProgramType.Y_PROTO,
false, false,
mustToken = false mustToken = false,
0.5F
), ),
) )
) )
val array = arrayOf("央视", "地方") val array = arrayOf("央视", "地方")
list = list.filterKeys { it in array } // list = list.filterKeys { it in array }
val listNew = mutableMapOf<String, List<TV>>() val listNew = mutableMapOf<String, List<TV>>()
var id = 0 var id = 0
@@ -15,7 +15,7 @@ class TVViewModel(private var tv: TV) : ViewModel() {
private var itemPosition: Int = 0 private var itemPosition: Int = 0
var retryTimes = 0 var retryTimes = 0
var retryMaxTimes = 1 var retryMaxTimes = 8
var authYSPRetryTimes = 0 var authYSPRetryTimes = 0
var authYSPRetryMaxTimes = 3 var authYSPRetryMaxTimes = 3
var tokenYSPRetryTimes = 0 var tokenYSPRetryTimes = 0
@@ -316,10 +316,11 @@ object Request {
val request = LiveInfoRequest(data) val request = LiveInfoRequest(data)
call = request.let { call = request.let {
yspApiService.getLiveInfo( yspApiService.getLiveInfo(
"guid=${YSP.getGuid()}; gr_user_id=261eecf2-0ce4-4316-a6a1-7171e3de7389; $cookie; newLogin=1; nseqId=${YSP.nseqId}; nrequest-id=${YSP.nrequest_id}", "guid=${YSP.getGuid()}; gr_user_id=1; $cookie; newLogin=1; nseqId=${YSP.nseqId}; nrequest-id=${YSP.nrequest_id}",
YSP.token, YSP.token,
YSP.yspsdkinput, YSP.yspsdkinput,
YSP.openapi_signature, YSP.openapi_signature,
YSP.yspticket,
"${YSP.nseqId}", "${YSP.nseqId}",
YSP.nrequest_id, YSP.nrequest_id,
"519748109", "519748109",
+24
View File
@@ -0,0 +1,24 @@
<!-- res/layout/fragment_progress_dialog.xml -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:padding="20dp">
<Button
android:id="@+id/btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/start_update"
tools:text="开始更新">
</Button>
<androidx.core.widget.ContentLoadingProgressBar
android:id="@+id/progressBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:indeterminate="false"
android:max="100"
android:progress="0"
android:progressDrawable="@android:drawable/progress_horizontal" />
</LinearLayout>
-9
View File
@@ -6,15 +6,6 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="@color/black" android:background="@color/black"
android:keepScreenOn="true"> android:keepScreenOn="true">
<SurfaceView
android:id="@+id/surface_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
app:resize_mode="fill"
app:use_controller="false" />
<androidx.media3.ui.PlayerView <androidx.media3.ui.PlayerView
android:id="@+id/player_view" android:id="@+id/player_view"
android:layout_width="match_parent" android:layout_width="match_parent"
+31 -11
View File
@@ -1,18 +1,22 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/setting" android:id="@+id/setting"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
> >
<LinearLayout <ScrollView
android:id="@+id/container"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content"> android:layout_height="match_parent"
android:fillViewport="true"
>
<LinearLayout <LinearLayout
android:id="@+id/content" android:id="@+id/content"
android:layout_width="300dp" android:layout_width="300dp"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical" android:orientation="vertical"
android:paddingTop="20dp" android:paddingTop="20dp"
android:paddingBottom="20dp"
android:paddingLeft="10dp" android:paddingLeft="10dp"
android:paddingRight="10dp" android:paddingRight="10dp"
android:background="@drawable/rounded_dark_left" android:background="@drawable/rounded_dark_left"
@@ -55,6 +59,22 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" /> android:layout_height="wrap_content" />
</LinearLayout> </LinearLayout>
<!-- <androidx.core.widget.ContentLoadingProgressBar-->
<!-- android:id="@+id/progressBar"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:indeterminate="false"-->
<!-- android:max="100"-->
<!-- android:progress="0"-->
<!-- android:visibility="gone"-->
<!-- android:progressDrawable="@android:drawable/progress_horizontal" />-->
<Button
android:id="@+id/clear"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="14sp"
android:text="@string/clear"
/>
<Button <Button
android:id="@+id/exit" android:id="@+id/exit"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@@ -98,11 +118,11 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" /> android:layout_height="wrap_content" />
</LinearLayout> </LinearLayout>
<ImageView </ScrollView>
android:id="@+id/appreciate" <ImageView
android:layout_width="300dp" android:id="@+id/appreciate"
android:layout_height="wrap_content" android:layout_width="300dp"
android:src="@drawable/appreciate" android:layout_height="wrap_content"
android:background="@drawable/rounded_white_right" /> android:src="@drawable/appreciate"
</LinearLayout> android:background="@drawable/rounded_white_right" />
</FrameLayout> </LinearLayout>
+2
View File
@@ -6,5 +6,7 @@
<string name="title_boot_startup">开机自启</string> <string name="title_boot_startup">开机自启</string>
<string name="title_grid">频道列表采用网格样式</string> <string name="title_grid">频道列表采用网格样式</string>
<string name="title_time">显示时间</string> <string name="title_time">显示时间</string>
<string name="clear">恢复默认</string>
<string name="exit">退出应用</string> <string name="exit">退出应用</string>
<string name="start_update">开始更新</string>
</resources> </resources>
+1 -1
View File
@@ -1 +1 @@
{"version_code": 33555200, "version_name": "v2.0.3"} {"version_code": 33620480, "version_name": "v2.1.2"}