From 1d7e2625f26c1499a5d9b29fcc49f197a9769159 Mon Sep 17 00:00:00 2001 From: Cuke <> Date: Wed, 29 Jun 2022 15:00:09 +0800 Subject: [PATCH] Complete play activity. --- .../osc/player/controller/VodController.java | 45 +++-- .../tvbox/osc/ui/activity/PlayActivity.java | 161 ++++++++++++------ app/src/main/res/drawable/icon_error.xml | 12 ++ app/src/main/res/layout/activity_play.xml | 42 ++++- .../res/layout/player_vod_control_view.xml | 23 ++- 5 files changed, 211 insertions(+), 72 deletions(-) create mode 100644 app/src/main/res/drawable/icon_error.xml diff --git a/app/src/main/java/com/github/tvbox/osc/player/controller/VodController.java b/app/src/main/java/com/github/tvbox/osc/player/controller/VodController.java index b1c24e4a..6a8cfcbb 100644 --- a/app/src/main/java/com/github/tvbox/osc/player/controller/VodController.java +++ b/app/src/main/java/com/github/tvbox/osc/player/controller/VodController.java @@ -85,12 +85,14 @@ public class VodController extends BaseController { LinearLayout mBottomRoot; LinearLayout mParseRoot; TvRecyclerView mGridView; + TextView mPlayTitle; TextView mNextBtn; TextView mPreBtn; TextView mPlayerScaleBtn; TextView mPlayerSpeedBtn; TextView mPlayerBtn; TextView mPlayerIJKBtn; + TextView mPlayerRetry; TextView mPlayerTimeStartBtn; TextView mPlayerTimeSkipBtn; TextView mPlayerTimeStepBtn; @@ -100,6 +102,7 @@ public class VodController extends BaseController { super.initView(); mCurrentTime = findViewById(R.id.curr_time); mTotalTime = findViewById(R.id.total_time); + mPlayTitle = findViewById(R.id.tv_info_name); mSeekBar = findViewById(R.id.seekBar); mProgressRoot = findViewById(R.id.tv_progress_container); mProgressIcon = findViewById(R.id.tv_progress_icon); @@ -107,6 +110,7 @@ public class VodController extends BaseController { mBottomRoot = findViewById(R.id.bottom_container); mParseRoot = findViewById(R.id.parse_root); mGridView = findViewById(R.id.mGridView); + mPlayerRetry = findViewById(R.id.play_retry); mNextBtn = findViewById(R.id.play_next); mPreBtn = findViewById(R.id.play_pre); mPlayerScaleBtn = findViewById(R.id.play_scale); @@ -129,6 +133,7 @@ public class VodController extends BaseController { ApiConfig.get().setDefaultParse(parseBean); parseAdapter.notifyItemChanged(position); listener.changeParse(parseBean); + hideBottom(); } }); mGridView.setAdapter(parseAdapter); @@ -166,7 +171,13 @@ public class VodController extends BaseController { mControlWrapper.startFadeOut(); } }); - + mPlayerRetry.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + listener.replay(); + hideBottom(); + } + }); mNextBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { @@ -205,7 +216,7 @@ public class VodController extends BaseController { float speed = (float) mPlayerConfig.getDouble("sp"); speed += 0.5f; if (speed > 3) - speed = 1; + speed = 0.5f; mPlayerConfig.put("sp", speed); updatePlayerCfgView(); listener.updatePlayerCfg(); @@ -340,7 +351,12 @@ public class VodController extends BaseController { } } + public void setTitle(String playTitleInfo) { + mPlayTitle.setText(playTitleInfo); + } + public void resetSpeed() { + skipEnd = true; mHandler.removeMessages(1004); mHandler.sendEmptyMessageDelayed(1004, 100); } @@ -356,7 +372,7 @@ public class VodController extends BaseController { void replay(); - void autoReplay(); + void errReplay(); } public void setListener(VodControlListener listener) { @@ -365,20 +381,25 @@ public class VodController extends BaseController { private VodControlListener listener; + private boolean skipEnd = true; + @Override protected void setProgress(int duration, int position) { if (mIsDragging) { return; } super.setProgress(duration, position); - int et = 0; - try { - et = mPlayerConfig.getInt("et"); - } catch (JSONException e) { - e.printStackTrace(); - } - if (position + (et * 1000) >= duration) { - listener.playNext(); + if (skipEnd && position != 0 && duration != 0) { + int et = 0; + try { + et = mPlayerConfig.getInt("et"); + } catch (JSONException e) { + e.printStackTrace(); + } + if (et > 0 && position + (et * 1000) >= duration) { + skipEnd = false; + listener.playNext(); + } } mCurrentTime.setText(PlayerUtils.stringForTime(position)); mTotalTime.setText(PlayerUtils.stringForTime(duration)); @@ -455,7 +476,7 @@ public class VodController extends BaseController { case VideoView.STATE_PAUSED: break; case VideoView.STATE_ERROR: - listener.autoReplay(); + listener.errReplay(); break; case VideoView.STATE_PREPARED: case VideoView.STATE_BUFFERED: diff --git a/app/src/main/java/com/github/tvbox/osc/ui/activity/PlayActivity.java b/app/src/main/java/com/github/tvbox/osc/ui/activity/PlayActivity.java index bf9d30e9..1adc8734 100644 --- a/app/src/main/java/com/github/tvbox/osc/ui/activity/PlayActivity.java +++ b/app/src/main/java/com/github/tvbox/osc/ui/activity/PlayActivity.java @@ -8,6 +8,8 @@ import android.graphics.Color; import android.net.http.SslError; import android.os.Build; import android.os.Bundle; +import android.os.Handler; +import android.os.Message; import android.view.KeyEvent; import android.view.View; import android.view.ViewGroup; @@ -20,6 +22,9 @@ import android.webkit.WebResourceResponse; import android.webkit.WebSettings; import android.webkit.WebView; import android.webkit.WebViewClient; +import android.widget.ImageView; +import android.widget.ProgressBar; +import android.widget.TextView; import android.widget.Toast; import androidx.annotation.NonNull; @@ -70,15 +75,14 @@ import me.jessyan.autosize.AutoSize; import xyz.doikki.videoplayer.player.ProgressManager; import xyz.doikki.videoplayer.player.VideoView; -/** - * @author pj567 - * @date :2020/12/22 - * @description: - */ public class PlayActivity extends BaseActivity { private VideoView mVideoView; + private TextView mPlayLoadTip; + private ImageView mPlayLoadErr; + private ProgressBar mPlayLoading; private VodController mController; private SourceViewModel sourceViewModel; + private Handler mHandler; @Override protected int getLayoutResID() { @@ -93,8 +97,22 @@ public class PlayActivity extends BaseActivity { } private void initView() { - setLoadSir(findViewById(R.id.rootLayout)); + mHandler = new Handler(new Handler.Callback() { + @Override + public boolean handleMessage(@NonNull Message msg) { + switch (msg.what) { + case 100: + stopParse(); + errorWithRetry("嗅探错误", false); + break; + } + return false; + } + }); mVideoView = findViewById(R.id.mVideoView); + mPlayLoadTip = findViewById(R.id.play_load_tip); + mPlayLoading = findViewById(R.id.play_loading); + mPlayLoadErr = findViewById(R.id.play_load_error); mController = new VodController(this); mController.setCanChangePosition(true); mController.setEnableInNormal(true); @@ -107,16 +125,20 @@ public class PlayActivity extends BaseActivity { @Override public long getSavedProgress(String url) { + int st = 0; + try { + st = mVodPlayerCfg.getInt("st"); + } catch (JSONException e) { + e.printStackTrace(); + } + long skip = st * 1000; if (CacheManager.getCache(MD5.string2MD5(url)) == null) { - int st = 0; - try { - st = mVodPlayerCfg.getInt("st"); - } catch (JSONException e) { - e.printStackTrace(); - } - return st * 1000; + return skip; } - return (long) CacheManager.getCache(MD5.string2MD5(url)); + long rec = (long) CacheManager.getCache(MD5.string2MD5(url)); + if (rec < skip) + return skip; + return rec; } }); mController.setListener(new VodController.VodControlListener() { @@ -132,6 +154,7 @@ public class PlayActivity extends BaseActivity { @Override public void changeParse(ParseBean pb) { + autoRetryCount = 0; doParse(pb); } @@ -143,51 +166,66 @@ public class PlayActivity extends BaseActivity { @Override public void replay() { + autoRetryCount = 0; play(); } @Override - public void autoReplay() { - + public void errReplay() { + errorWithRetry("视频播放出错", false); } }); mVideoView.setVideoController(mController); } - void getPlayInfoError() { - runOnUiThread(new Runnable() { - @Override - public void run() { - Toast.makeText(mContext, "获取播放信息错误", Toast.LENGTH_SHORT).show(); - finish(); - } - }); + void setTip(String msg, boolean loading, boolean err) { + mPlayLoadTip.setText(msg); + mPlayLoadTip.setVisibility(View.VISIBLE); + mPlayLoading.setVisibility(loading ? View.VISIBLE : View.GONE); + mPlayLoadErr.setVisibility(err ? View.VISIBLE : View.GONE); } - void parseError() { - runOnUiThread(new Runnable() { - @Override - public void run() { - Toast.makeText(mContext, "解析错误", Toast.LENGTH_SHORT).show(); - } - }); + void hideTip() { + mPlayLoadTip.setVisibility(View.GONE); + mPlayLoading.setVisibility(View.GONE); + mPlayLoadErr.setVisibility(View.GONE); + } + + void errorWithRetry(String err, boolean finish) { + if (!autoRetry()) { + runOnUiThread(new Runnable() { + @Override + public void run() { + if (finish) { + Toast.makeText(mContext, err, Toast.LENGTH_SHORT).show(); + finish(); + } else { + setTip(err, false, true); + } + } + }); + } } void playUrl(String url, HashMap headers) { runOnUiThread(new Runnable() { @Override public void run() { + stopParse(); if (mVideoView != null) { mVideoView.release(); - PlayerHelper.updateCfg(mVideoView, mVodPlayerCfg); - mVideoView.setProgressKey(progressKey); - if (headers != null) { - mVideoView.setUrl(url, headers); - } else { - mVideoView.setUrl(url); + if (url != null) { + hideTip(); + PlayerHelper.updateCfg(mVideoView, mVodPlayerCfg); + mVideoView.setProgressKey(progressKey); + if (headers != null) { + mVideoView.setUrl(url, headers); + } else { + mVideoView.setUrl(url); + } + mVideoView.start(); + mController.resetSpeed(); } - mVideoView.start(); - mController.resetSpeed(); } } }); @@ -198,7 +236,6 @@ public class PlayActivity extends BaseActivity { sourceViewModel.playResult.observe(this, new Observer() { @Override public void onChanged(JSONObject info) { - showSuccess(); if (info != null) { try { progressKey = info.optString("proKey", null); @@ -231,10 +268,10 @@ public class PlayActivity extends BaseActivity { playUrl(playUrl + url, headers); } } catch (Throwable th) { - getPlayInfoError(); + errorWithRetry("获取播放信息错误", true); } } else { - getPlayInfoError(); + errorWithRetry("获取播放信息错误", true); } } }); @@ -365,11 +402,27 @@ public class PlayActivity extends BaseActivity { play(); } + private int autoRetryCount = 0; + + boolean autoRetry() { + if (autoRetryCount < 3) { + autoRetryCount++; + play(); + return true; + } else { + autoRetryCount = 0; + return false; + } + } public void play() { VodInfo.VodSeries vs = mVodInfo.seriesMap.get(mVodInfo.playFlag).get(mVodInfo.playIndex); EventBus.getDefault().post(new RefreshEvent(RefreshEvent.TYPE_REFRESH, mVodInfo.playIndex)); - showLoading(); + setTip("正在获取播放信息", true, false); + String playTitleInfo = mVodInfo.name + " " + vs.name; + mController.setTitle(playTitleInfo); + + playUrl(null, null); String progressKey = mVodInfo.sourceKey + mVodInfo.id + mVodInfo.playFlag + mVodInfo.playIndex; sourceViewModel.getPlay(sourceKey, mVodInfo.playFlag, progressKey, vs.url); } @@ -420,7 +473,9 @@ public class PlayActivity extends BaseActivity { } void stopParse() { + mHandler.removeMessages(100); stopLoadWebView(false); + loadFound = false; OkGo.getInstance().cancelTag("json_jx"); if (parseThreadPool != null) { try { @@ -437,8 +492,12 @@ public class PlayActivity extends BaseActivity { private void doParse(ParseBean pb) { stopParse(); if (pb.getType() == 0) { + setTip("正在嗅探播放地址", true, false); + mHandler.removeMessages(100); + mHandler.sendEmptyMessageDelayed(100, 15 * 1000); loadWebView(pb.getUrl() + webUrl); } else if (pb.getType() == 1) { // json 解析 + setTip("正在解析播放地址", true, false); OkGo.get(pb.getUrl() + webUrl) .tag("json_jx") .execute(new AbsCallback() { @@ -475,17 +534,18 @@ public class PlayActivity extends BaseActivity { playUrl(rs.getString("url"), headers); } catch (JSONException e) { e.printStackTrace(); - parseError(); + errorWithRetry("解析错误", false); } } @Override public void onError(Response response) { super.onError(response); - parseError(); + errorWithRetry("解析错误", false); } }); } else if (pb.getType() == 2) { // json 扩展 + setTip("正在解析播放地址", true, false); parseThreadPool = Executors.newSingleThreadExecutor(); LinkedHashMap jxs = new LinkedHashMap<>(); for (ParseBean p : ApiConfig.get().getParseBeanList()) { @@ -498,7 +558,7 @@ public class PlayActivity extends BaseActivity { public void run() { JSONObject rs = ApiConfig.get().jsonExt(pb.getUrl(), jxs, webUrl); if (rs == null || !rs.has("url")) { - parseError(); + errorWithRetry("解析错误", false); } else { HashMap headers = null; if (rs.has("header")) { @@ -527,6 +587,7 @@ public class PlayActivity extends BaseActivity { } }); } else if (pb.getType() == 3) { // json 聚合 + setTip("正在解析播放地址", true, false); parseThreadPool = Executors.newSingleThreadExecutor(); LinkedHashMap> jxs = new LinkedHashMap<>(); String extendName = ""; @@ -546,7 +607,7 @@ public class PlayActivity extends BaseActivity { public void run() { JSONObject rs = ApiConfig.get().jsonExtMix(parseFlag, pb.getUrl(), finalExtendName, jxs, webUrl); if (rs == null || !rs.has("url")) { - parseError(); + errorWithRetry("解析错误", false); } else { HashMap headers = null; if (rs.has("header")) { @@ -648,9 +709,9 @@ public class PlayActivity extends BaseActivity { if (mXwalkWebView != null) { mXwalkWebView.stopLoading(); - mXwalkWebView.clearCache(true); mXwalkWebView.loadUrl("about:blank"); if (destroy) { + mXwalkWebView.clearCache(true); mXwalkWebView.removeAllViews(); mXwalkWebView.onDestroy(); mXwalkWebView = null; @@ -658,9 +719,9 @@ public class PlayActivity extends BaseActivity { } if (mSysWebView != null) { mSysWebView.stopLoading(); - mSysWebView.clearCache(true); mSysWebView.loadUrl("about:blank"); if (destroy) { + mSysWebView.clearCache(true); mSysWebView.removeAllViews(); mSysWebView.destroy(); mSysWebView = null; @@ -792,6 +853,7 @@ public class PlayActivity extends BaseActivity { if (!ad && !loadFound) { if (DefaultConfig.isVideoFormat(url)) { + mHandler.removeMessages(100); loadFound = true; if (headers != null && !headers.isEmpty()) { playUrl(url, headers); @@ -947,6 +1009,7 @@ public class PlayActivity extends BaseActivity { } if (!ad && !loadFound) { if (DefaultConfig.isVideoFormat(url)) { + mHandler.removeMessages(100); loadFound = true; HashMap webHeaders = new HashMap<>(); try { diff --git a/app/src/main/res/drawable/icon_error.xml b/app/src/main/res/drawable/icon_error.xml new file mode 100644 index 00000000..4799b428 --- /dev/null +++ b/app/src/main/res/drawable/icon_error.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/layout/activity_play.xml b/app/src/main/res/layout/activity_play.xml index fa6d0234..9ee7ed8e 100644 --- a/app/src/main/res/layout/activity_play.xml +++ b/app/src/main/res/layout/activity_play.xml @@ -1,18 +1,44 @@ - + android:layout_height="match_parent" /> + + - - + + \ No newline at end of file diff --git a/app/src/main/res/layout/player_vod_control_view.xml b/app/src/main/res/layout/player_vod_control_view.xml index 9c5fe6c4..5aa9ab16 100644 --- a/app/src/main/res/layout/player_vod_control_view.xml +++ b/app/src/main/res/layout/player_vod_control_view.xml @@ -36,6 +36,19 @@ android:textColor="@color/color_CC000000" android:textSize="@dimen/ts_20" /> + + @@ -260,6 +273,9 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="left" + android:ellipsize="end" + android:maxLines="1" + android:padding="@dimen/vs_20" android:text="http://" android:textColor="@android:color/white" android:textSize="@dimen/ts_24" /> @@ -356,6 +372,7 @@ android:indeterminateBehavior="repeat" android:indeterminateDrawable="@drawable/anim_loading" android:indeterminateOnly="true" - android:tag="vod_control_loading" /> + android:tag="vod_control_loading" + android:visibility="gone" /> \ No newline at end of file