diff --git a/app/src/leanback/java/com/fongmi/android/tv/ui/activity/DetailActivity.java b/app/src/leanback/java/com/fongmi/android/tv/ui/activity/DetailActivity.java index 8068d2f71..7c23ef880 100644 --- a/app/src/leanback/java/com/fongmi/android/tv/ui/activity/DetailActivity.java +++ b/app/src/leanback/java/com/fongmi/android/tv/ui/activity/DetailActivity.java @@ -101,7 +101,6 @@ public class DetailActivity extends BaseActivity implements CustomKeyDownVod.Lis private int mCurrent; private Runnable mR1; private Runnable mR2; - private Runnable mR3; public static void start(Activity activity, String id, String name) { start(activity, ApiConfig.get().getHome().getKey(), id, name); @@ -189,7 +188,6 @@ public class DetailActivity extends BaseActivity implements CustomKeyDownVod.Lis mFrameParams = mBinding.video.getLayoutParams(); mBinding.progressLayout.showProgress(); mPlayers = new Players().init(); - mR3 = ErrorEvent::timeout; mR1 = this::hideControl; mR2 = this::setTraffic; setRecyclerView(); @@ -333,7 +331,6 @@ public class DetailActivity extends BaseActivity implements CustomKeyDownVod.Lis if (result != null) { mBinding.control.parseLayout.setVisibility(mParseAdapter.size() > 0 && useParse ? View.VISIBLE : View.GONE); mPlayers.start(result, useParse); - setR3Callback(); } else { ErrorEvent.url(); } @@ -662,11 +659,6 @@ public class DetailActivity extends BaseActivity implements CustomKeyDownVod.Lis App.post(mR1, Constant.INTERVAL_HIDE); } - private void setR3Callback() { - App.removeCallbacks(mR3); - App.post(mR3, Constant.TIMEOUT_VOD); - } - private void getPart(String source) { OkHttp.newCall("http://api.pullword.com/get.php?source=" + URLEncoder.encode(source.trim()) + "¶m1=0¶m2=0&json=1").enqueue(new Callback() { @Override @@ -775,7 +767,6 @@ public class DetailActivity extends BaseActivity implements CustomKeyDownVod.Lis mPlayers.reset(); setDefaultTrack(); setTrackVisible(true); - App.removeCallbacks(mR3); mBinding.widget.size.setText(mPlayers.getSizeText()); break; case Player.STATE_ENDED: @@ -811,7 +802,6 @@ public class DetailActivity extends BaseActivity implements CustomKeyDownVod.Lis private void onError(ErrorEvent event) { Clock.get().setCallback(null); showError(event.getMsg()); - App.removeCallbacks(mR3); hideProgress(); mPlayers.reset(); checkError(event); @@ -1045,6 +1035,6 @@ public class DetailActivity extends BaseActivity implements CustomKeyDownVod.Lis protected void onDestroy() { super.onDestroy(); mPlayers.release(); - App.removeCallbacks(mR1, mR2, mR3); + App.removeCallbacks(mR1, mR2); } } diff --git a/app/src/leanback/java/com/fongmi/android/tv/ui/activity/LiveActivity.java b/app/src/leanback/java/com/fongmi/android/tv/ui/activity/LiveActivity.java index fdb4e0deb..34bc39bde 100644 --- a/app/src/leanback/java/com/fongmi/android/tv/ui/activity/LiveActivity.java +++ b/app/src/leanback/java/com/fongmi/android/tv/ui/activity/LiveActivity.java @@ -86,7 +86,6 @@ public class LiveActivity extends BaseActivity implements GroupPresenter.OnClick private Runnable mR2; private Runnable mR3; private Runnable mR4; - private Runnable mR5; private int count; public static void start(Activity activity) { @@ -133,7 +132,6 @@ public class LiveActivity extends BaseActivity implements GroupPresenter.OnClick mR2 = this::hideControl; mR3 = this::setChannelActivated; mR4 = this::setTraffic; - mR5 = this::onError; mPlayers = new Players().init(); mKeyDown = CustomKeyDownLive.create(this); mFormatDate = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()); @@ -209,10 +207,8 @@ public class LiveActivity extends BaseActivity implements GroupPresenter.OnClick private void setViewModel() { mViewModel = new ViewModelProvider(this).get(LiveViewModel.class); - mViewModel.result.observe(this, result -> { - if (result instanceof Live) setGroup((Live) result); - else if (result instanceof Channel) mPlayers.start((Channel) result); - }); + mViewModel.channel.observe(this, result -> mPlayers.start(result)); + mViewModel.live.observe(this, this::setGroup); } private void getLive() { @@ -397,11 +393,6 @@ public class LiveActivity extends BaseActivity implements GroupPresenter.OnClick App.post(mR2, Constant.INTERVAL_HIDE); } - private void setR5Callback() { - App.removeCallbacks(mR5); - App.post(mR5, Constant.TIMEOUT_LIVE); - } - private void resetPass() { this.count = 0; } @@ -487,7 +478,6 @@ public class LiveActivity extends BaseActivity implements GroupPresenter.OnClick private void getUrl() { mViewModel.getUrl(mChannel); - setR5Callback(); showProgress(); } @@ -674,7 +664,6 @@ public class LiveActivity extends BaseActivity implements GroupPresenter.OnClick hideProgress(); mPlayers.reset(); setTrackVisible(true); - App.removeCallbacks(mR5); break; case Player.STATE_ENDED: onKeyDown(); @@ -694,7 +683,6 @@ public class LiveActivity extends BaseActivity implements GroupPresenter.OnClick } private void onError() { - App.removeCallbacks(mR5); mPlayers.reset(); checkNext(); } @@ -742,6 +730,6 @@ public class LiveActivity extends BaseActivity implements GroupPresenter.OnClick Force.get().stop(); ZLive.get().stop(); TVBus.get().quit(); - App.removeCallbacks(mR1, mR2, mR3, mR4, mR5); + App.removeCallbacks(mR1, mR2, mR3, mR4); } } diff --git a/app/src/main/java/com/fongmi/android/tv/Constant.java b/app/src/main/java/com/fongmi/android/tv/Constant.java index cdb956f8b..9878775a6 100644 --- a/app/src/main/java/com/fongmi/android/tv/Constant.java +++ b/app/src/main/java/com/fongmi/android/tv/Constant.java @@ -1,29 +1,32 @@ package com.fongmi.android.tv; public class Constant { - - //快進時間單位 10 秒 + //快進時間單位 public static final int INTERVAL_SEEK = 10 * 1000; - //控件隱藏時間 5 秒 + //控件隱藏時間 public static final int INTERVAL_HIDE = 5 * 1000; - //網路偵測間隔 0.5 秒 + //網路偵測間隔 public static final int INTERVAL_TRAFFIC = 500; - //點播超時時間 15 秒 - public static final int TIMEOUT_VOD = 15 * 1000; - //直播超時時間 10 秒 + //點播爬蟲時間 + public static final int TIMEOUT_VOD = 30 * 1000; + //直播解析時間 public static final int TIMEOUT_LIVE = 10 * 1000; - //解析超時時間 30 秒 + //播放超時時間 + public static final int TIMEOUT_PLAY = 15 * 1000; + //解析預設時間 + public static final int TIMEOUT_PARSE_DEF = 5 * 1000; + //解析超時時間 public static final int TIMEOUT_PARSE_WEB = 15 * 1000; - //解析超時時間 10 秒 + //解析超時時間 public static final int TIMEOUT_PARSE_JSON = 10 * 1000; - //解析超時時間 15 秒 + //解析超時時間 public static final int TIMEOUT_PARSE_JSON_EXT = 15 * 1000; - //解析超時時間 15 秒 + //解析超時時間 public static final int TIMEOUT_PARSE_JSON_MIX = 15 * 1000; - //網路超時時間 30 秒 + //網路超時時間 public static final int TIMEOUT_HTTP = 30 * 1000; - //代理超時時間 5 秒 + //代理超時時間 public static final int TIMEOUT_GITHUB = 5 * 1000; - //搜尋線程數量 5 個 + //搜尋線程數量 public static final int THREAD_POOL = 5; } diff --git a/app/src/main/java/com/fongmi/android/tv/bean/Channel.java b/app/src/main/java/com/fongmi/android/tv/bean/Channel.java index 72710ca34..709c011cf 100644 --- a/app/src/main/java/com/fongmi/android/tv/bean/Channel.java +++ b/app/src/main/java/com/fongmi/android/tv/bean/Channel.java @@ -120,7 +120,7 @@ public class Channel { } public String getUrl() { - return url; + return TextUtils.isEmpty(url) ? "" : url; } public void setUrl(String url) { diff --git a/app/src/main/java/com/fongmi/android/tv/model/LiveViewModel.java b/app/src/main/java/com/fongmi/android/tv/model/LiveViewModel.java index e03bede6d..2a404211a 100644 --- a/app/src/main/java/com/fongmi/android/tv/model/LiveViewModel.java +++ b/app/src/main/java/com/fongmi/android/tv/model/LiveViewModel.java @@ -18,22 +18,27 @@ import java.util.concurrent.TimeUnit; public class LiveViewModel extends ViewModel { - public MutableLiveData result; + private static final int LIVE = 1; + private static final int CHANNEL = 2; + + public MutableLiveData channel; + public MutableLiveData live; public ExecutorService executor; public LiveViewModel() { - this.result = new MutableLiveData<>(); + this.channel = new MutableLiveData<>(); + this.live = new MutableLiveData<>(); } - public void getLive(Live home) { - execute(() -> { - LiveParser.start(home); - return home; + public void getLive(Live item) { + execute(LIVE, () -> { + LiveParser.start(item); + return item; }); } public void getUrl(Channel item) { - execute(() -> { + execute(CHANNEL, () -> { TVBus.get().stop(); String url = item.getCurrent().split("\\$")[0]; if (item.isForce()) item.setUrl(Force.get().fetch(url)); @@ -44,14 +49,18 @@ public class LiveViewModel extends ViewModel { }); } - private void execute(Callable callable) { + private void execute(int type, Callable callable) { if (executor != null) executor.shutdownNow(); executor = Executors.newFixedThreadPool(2); executor.execute(() -> { try { - if (!Thread.interrupted()) result.postValue(executor.submit(callable).get(Constant.TIMEOUT_LIVE, TimeUnit.MILLISECONDS)); + if (!Thread.interrupted() && type == LIVE) live.postValue((Live) executor.submit(callable).get(Constant.TIMEOUT_HTTP, TimeUnit.MILLISECONDS)); + if (!Thread.interrupted() && type == CHANNEL) channel.postValue((Channel) executor.submit(callable).get(Constant.TIMEOUT_LIVE, TimeUnit.MILLISECONDS)); } catch (Throwable e) { e.printStackTrace(); + if (e instanceof InterruptedException) return; + if (!Thread.interrupted() && type == LIVE) live.postValue(new Live()); + if (!Thread.interrupted() && type == CHANNEL) channel.postValue(new Channel()); } }); } diff --git a/app/src/main/java/com/fongmi/android/tv/player/ParseTask.java b/app/src/main/java/com/fongmi/android/tv/player/ParseTask.java index 762ea690b..8475017d1 100644 --- a/app/src/main/java/com/fongmi/android/tv/player/ParseTask.java +++ b/app/src/main/java/com/fongmi/android/tv/player/ParseTask.java @@ -58,6 +58,7 @@ public class ParseTask { try { executor.submit(getTask(result)).get(getTimeout(), TimeUnit.MILLISECONDS); } catch (Throwable e) { + ; onParseError(); } }); @@ -75,8 +76,6 @@ public class ParseTask { private int getTimeout() { switch (parse.getType()) { - case 0: //嗅探 - return Constant.TIMEOUT_PARSE_WEB; case 1: //Json return Constant.TIMEOUT_PARSE_JSON; case 2: //Json 擴展 @@ -84,7 +83,7 @@ public class ParseTask { case 3: //聚合 return Constant.TIMEOUT_PARSE_JSON_MIX; default: - return Constant.TIMEOUT_VOD; + return Constant.TIMEOUT_PARSE_DEF; } } @@ -152,18 +151,20 @@ public class ParseTask { private void onParseSuccess(Map headers, String url, String from) { App.post(() -> { if (callback != null) callback.onParseSuccess(headers, url, from); + stop(); }); } private void onParseError() { App.post(() -> { if (callback != null) callback.onParseError(); + stop(); }); } - public void cancel() { + public void stop() { if (executor != null) executor.shutdownNow(); - if (webView != null) webView.stop(); + if (webView != null) webView.stop(false); executor = null; callback = null; webView = null; diff --git a/app/src/main/java/com/fongmi/android/tv/player/Players.java b/app/src/main/java/com/fongmi/android/tv/player/Players.java index b3e50e715..8b2c8f681 100644 --- a/app/src/main/java/com/fongmi/android/tv/player/Players.java +++ b/app/src/main/java/com/fongmi/android/tv/player/Players.java @@ -5,6 +5,7 @@ import android.net.Uri; import androidx.annotation.NonNull; import com.fongmi.android.tv.App; +import com.fongmi.android.tv.Constant; import com.fongmi.android.tv.R; import com.fongmi.android.tv.api.ApiConfig; import com.fongmi.android.tv.bean.Channel; @@ -41,6 +42,7 @@ public class Players implements Player.Listener, IMediaPlayer.OnInfoListener, IM private Formatter formatter; private ParseTask parseTask; private ExoPlayer exoPlayer; + private Runnable timeout; private int errorCode; private int retry; private int decode; @@ -57,6 +59,7 @@ public class Players implements Player.Listener, IMediaPlayer.OnInfoListener, IM public Players init() { player = Prefers.getPlayer(); decode = Prefers.getDecode(); + timeout = ErrorEvent::timeout; builder = new StringBuilder(); formatter = new Formatter(builder, Locale.getDefault()); return this; @@ -264,7 +267,11 @@ public class Players implements Player.Listener, IMediaPlayer.OnInfoListener, IM } public void start(Channel channel) { - setMediaSource(channel.getHeaders(), channel.getUrl()); + if (channel.getUrl().isEmpty()) { + ErrorEvent.url(); + } else { + setMediaSource(channel.getHeaders(), channel.getUrl()); + } } public void start(Result result, boolean useParse) { @@ -319,11 +326,15 @@ public class Players implements Player.Listener, IMediaPlayer.OnInfoListener, IM } private void stopParse() { - if (parseTask != null) parseTask.cancel(); + if (parseTask != null) parseTask.stop(); } private boolean isAds(String url) { - return ApiConfig.get().getAds().contains(Uri.parse(url).getHost()); + try { + return ApiConfig.get().getAds().contains(Uri.parse(url).getHost()); + } catch (Exception e) { + return false; + } } private void setMediaSource(Result result) { @@ -331,7 +342,7 @@ public class Players implements Player.Listener, IMediaPlayer.OnInfoListener, IM if (isIjk()) ijkPlayer.setMediaSource(result.getPlayUrl() + result.getUrl(), result.getHeaders()); if (isExo()) exoPlayer.setMediaSource(ExoUtil.getSource(result, errorCode)); if (isExo()) exoPlayer.prepare(); - PlayerEvent.state(0); + setTimeoutCheck(); } private void setMediaSource(Map headers, String url) { @@ -339,7 +350,13 @@ public class Players implements Player.Listener, IMediaPlayer.OnInfoListener, IM if (isIjk()) ijkPlayer.setMediaSource(url, headers); if (isExo()) exoPlayer.setMediaSource(ExoUtil.getSource(headers, url, errorCode)); if (isExo()) exoPlayer.prepare(); + setTimeoutCheck(); + } + + private void setTimeoutCheck() { PlayerEvent.state(0); + App.removeCallbacks(timeout); + App.post(timeout, Constant.TIMEOUT_PLAY); } private void setTrack(Track item) { @@ -377,11 +394,13 @@ public class Players implements Player.Listener, IMediaPlayer.OnInfoListener, IM @Override public void onPlayerError(@NonNull PlaybackException error) { this.errorCode = error.errorCode; + App.removeCallbacks(timeout); ErrorEvent.format(); } @Override public void onPlaybackStateChanged(int state) { + if (state == Player.STATE_READY) App.removeCallbacks(timeout); PlayerEvent.state(state); } @@ -395,6 +414,7 @@ public class Players implements Player.Listener, IMediaPlayer.OnInfoListener, IM case IMediaPlayer.MEDIA_INFO_VIDEO_SEEK_RENDERING_START: case IMediaPlayer.MEDIA_INFO_AUDIO_SEEK_RENDERING_START: PlayerEvent.state(Player.STATE_READY); + App.removeCallbacks(timeout); return true; default: return true; @@ -403,6 +423,7 @@ public class Players implements Player.Listener, IMediaPlayer.OnInfoListener, IM @Override public boolean onError(IMediaPlayer mp, int what, int extra) { + App.removeCallbacks(timeout); ErrorEvent.format(); return true; } @@ -410,6 +431,7 @@ public class Players implements Player.Listener, IMediaPlayer.OnInfoListener, IM @Override public void onPrepared(IMediaPlayer mp) { PlayerEvent.state(Player.STATE_READY); + App.removeCallbacks(timeout); } @Override diff --git a/app/src/main/java/com/fongmi/android/tv/ui/custom/CustomWebView.java b/app/src/main/java/com/fongmi/android/tv/ui/custom/CustomWebView.java index 317028d0a..73bfc2d13 100644 --- a/app/src/main/java/com/fongmi/android/tv/ui/custom/CustomWebView.java +++ b/app/src/main/java/com/fongmi/android/tv/ui/custom/CustomWebView.java @@ -16,6 +16,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.fongmi.android.tv.App; +import com.fongmi.android.tv.Constant; import com.fongmi.android.tv.api.ApiConfig; import com.fongmi.android.tv.bean.Site; import com.fongmi.android.tv.player.ParseTask; @@ -33,6 +34,7 @@ public class CustomWebView extends WebView { private ParseTask.Callback callback; private WebResourceResponse empty; private List keys; + private Runnable mTimer; private String key; public static CustomWebView create(@NonNull Context context) { @@ -68,6 +70,7 @@ public class CustomWebView extends WebView { } public CustomWebView start(String key, String url, Map headers, ParseTask.Callback callback) { + App.post(mTimer = () -> stop(true), Constant.TIMEOUT_PARSE_WEB); this.callback = callback; setUserAgent(headers); loadUrl(url, headers); @@ -116,15 +119,21 @@ public class CustomWebView extends WebView { App.post(() -> onSuccess(news, url)); } - public void stop() { + public void stop(boolean error) { stopLoading(); loadUrl("about:blank"); - callback = null; + App.removeCallbacks(mTimer); + if (error) App.post(this::onError); } private void onSuccess(Map news, String url) { if (callback != null) callback.onParseSuccess(news, url, ""); callback = null; - stop(); + stop(false); + } + + private void onError() { + if (callback != null) callback.onParseError(); + callback = null; } }