pull/144/head
21561 1 year ago
parent 99960433a3
commit cbe8119676
  1. 76
      app/src/main/java/com/github/tvbox/osc/ui/activity/LivePlayActivity.java
  2. 39
      app/src/python/java/com/undcover/freedom/pyramid/PythonLoader.java

@ -1,5 +1,6 @@
package com.github.tvbox.osc.ui.activity;
import android.Manifest;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.IntEvaluator;
@ -1457,25 +1458,33 @@ public class LivePlayActivity extends BaseActivity {
@Override
public void playStateChanged(int playState) {
mHandler.removeCallbacks(mConnectTimeoutChangeSourceRun);
switch (playState) {
case VideoView.STATE_IDLE:
// 空闲状态:播放器处于空闲,尚未开始播放。一般不需要自动换源。
case VideoView.STATE_PAUSED:
// 暂停状态:播放被暂停,通常是用户操作,不触发自动换源
break;
case VideoView.STATE_PREPARED:
// 准备就绪:播放器已经加载好媒体数据,但尚未开始播放。
case VideoView.STATE_BUFFERED:
case VideoView.STATE_PLAYING:
// 播放状态:当播放器缓冲完成或正在正常播放时,表明当前源是可用的,
currentLiveChangeSourceTimes = 0;
mHandler.removeCallbacks(mConnectTimeoutChangeSourceRun);
break;
case VideoView.STATE_ERROR:
case VideoView.STATE_PLAYBACK_COMPLETED:
mHandler.removeCallbacks(mConnectTimeoutChangeSourceRun);
mHandler.postDelayed(mConnectTimeoutChangeSourceRun, 3000);
// 错误或播放结束状态:播放器遇到错误或播放完毕时,
// 启动自动换源任务,等待3秒后尝试切换至备选源
mHandler.postDelayed(mConnectTimeoutChangeSourceRun, 3500);
break;
case VideoView.STATE_PREPARING:
case VideoView.STATE_BUFFERING:
mHandler.removeCallbacks(mConnectTimeoutChangeSourceRun);
mHandler.postDelayed(mConnectTimeoutChangeSourceRun, (Hawk.get(HawkConfig.LIVE_CONNECT_TIMEOUT, 1) + 1) * 5000);
// 正在准备或缓冲状态:表示当前源正在加载中
mHandler.postDelayed(mConnectTimeoutChangeSourceRun, (Hawk.get(HawkConfig.LIVE_CONNECT_TIMEOUT, 1) + 1) * 5000L);
break;
default:
LOG.i("echo-Unexpected live_play state: " + playState);
break;
}
}
@ -1798,6 +1807,10 @@ public class LivePlayActivity extends BaseActivity {
break;
case 5://多源切换
//TODO
if (mVideoView != null) {
mVideoView.release();
mVideoView=null;
}
if(position==Hawk.get(HawkConfig.LIVE_GROUP_INDEX, 0))break;
JsonArray live_groups=Hawk.get(HawkConfig.LIVE_GROUP_LIST,new JsonArray());
JsonObject livesOBJ = live_groups.get(position).getAsJsonObject();
@ -1816,10 +1829,6 @@ public class LivePlayActivity extends BaseActivity {
liveSettingItemAdapter.selectItem(position, true, true);
Hawk.put(HawkConfig.LIVE_GROUP_INDEX, position);
ApiConfig.get().loadLiveApi(livesOBJ);
if (mVideoView != null) {
mVideoView.release();
mVideoView=null;
}
recreate();
return;
}
@ -1875,6 +1884,11 @@ public class LivePlayActivity extends BaseActivity {
LOG.i("echo-live-url:"+url);
if(url.contains(".py")){
if (!hasPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
Toast.makeText(App.getInstance(), "该源需要存储权限", Toast.LENGTH_SHORT).show();
finish();
return;
}
String finalUrl = url;
Runnable waitResponse = new Runnable() {
@Override
@ -1892,7 +1906,7 @@ public class LivePlayActivity extends BaseActivity {
});
String sortJson = null;
try {
sortJson = future.get(6, TimeUnit.SECONDS);
sortJson = future.get(10, TimeUnit.SECONDS);
} catch (TimeoutException e) {
e.printStackTrace();
future.cancel(true);
@ -1928,8 +1942,13 @@ public class LivePlayActivity extends BaseActivity {
ApiConfig.get().loadLives(livesArray);
List<LiveChannelGroup> list = ApiConfig.get().getChannelGroupList();
if (list.isEmpty()) {
Toast.makeText(App.getInstance(), "频道列表为空", Toast.LENGTH_SHORT).show();
finish();
mHandler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(App.getInstance(), "频道列表为空", Toast.LENGTH_SHORT).show();
finish();
}
});
return;
}
liveChannelGroupList.clear();
@ -2005,6 +2024,39 @@ public class LivePlayActivity extends BaseActivity {
}
}
private void autoSwitchNextLive(){
Toast.makeText(App.getInstance(), "加载错误,自动切换下一个源", Toast.LENGTH_SHORT).show();
JsonArray live_groups=Hawk.get(HawkConfig.LIVE_GROUP_LIST,new JsonArray());
int position=Hawk.get(HawkConfig.LIVE_GROUP_INDEX,0)+1;
if(position>live_groups.size()-1){
Hawk.put(HawkConfig.LIVE_GROUP_INDEX,0);
Toast.makeText(App.getInstance(), "当前无有效直播,自动退出到主页", Toast.LENGTH_SHORT).show();
jumpActivity(HomeActivity.class);
}
JsonObject livesOBJ = live_groups.get(position).getAsJsonObject();
if(livesOBJ.has("type")){
String type= livesOBJ.get("type").getAsString();
if(!type.equals("0") && !type.equals("3")){
Toast.makeText(App.getInstance(), "暂不支持该直播类型", Toast.LENGTH_SHORT).show();
autoSwitchNextLive();
}
}else {
if(!livesOBJ.has("channels")){
Toast.makeText(App.getInstance(), "暂不支持该直播类型", Toast.LENGTH_SHORT).show();
autoSwitchNextLive();
}
}
liveSettingItemAdapter.selectItem(position, true, true);
Hawk.put(HawkConfig.LIVE_GROUP_INDEX, position);
ApiConfig.get().loadLiveApi(livesOBJ);
if (mVideoView != null) {
mVideoView.release();
mVideoView=null;
}
recreate();
}
private void initLiveState() {
String lastChannelName = Hawk.get(HawkConfig.LIVE_CHANNEL, "");

@ -25,6 +25,12 @@ import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import okhttp3.Call;
import okhttp3.Response;
@ -120,26 +126,39 @@ public class PythonLoader {
PyLog.d(key + " :缓存加载成功!");
return spiders.get(key);
}
// 使用ExecutorService来管理线程
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<?> future = null;
try {
PythonSpider sp = new PythonSpider(key, cache);
Thread initThread = new Thread(() -> {
// 提交初始化任务
future = executor.submit(() -> {
try {
sp.init(app, url);
} catch (Exception e) {
e.printStackTrace();
}
});
initThread.start();
initThread.join(12_000);
if (initThread.isAlive()) {
PyLog.e("echo-init方法执行超时超时");
initThread.interrupt();
return new SpiderNull();
}
// 等待线程完成,最多10秒
future.get(10, TimeUnit.SECONDS);
// 任务成功,缓存并返回
spiders.put(key, sp);
return sp;
} catch (Throwable th) {
PyLog.e(th.toString());
} catch (TimeoutException e) {
PyLog.e("echo-init方法执行超时");
// 超时了,不做中断,返回空的Spider
} catch (ExecutionException | InterruptedException e) {
PyLog.e("echo-init:ExecutionException|InterruptedException");
} finally {
// 关闭线程池
if (future != null && !future.isDone()) {
future.cancel(true); // 取消任务
}
executor.shutdown(); // 关闭线程池
}
return new SpiderNull();
}

Loading…
Cancel
Save