Complete play activity.

pull/1/head
Cuke 4 years ago
parent 6d3a8e47f2
commit 1d7e2625f2
  1. 45
      app/src/main/java/com/github/tvbox/osc/player/controller/VodController.java
  2. 161
      app/src/main/java/com/github/tvbox/osc/ui/activity/PlayActivity.java
  3. 12
      app/src/main/res/drawable/icon_error.xml
  4. 42
      app/src/main/res/layout/activity_play.xml
  5. 23
      app/src/main/res/layout/player_vod_control_view.xml

@ -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:

@ -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<String, String> 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<JSONObject>() {
@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.<String>get(pb.getUrl() + webUrl)
.tag("json_jx")
.execute(new AbsCallback<String>() {
@ -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<String> response) {
super.onError(response);
parseError();
errorWithRetry("解析错误", false);
}
});
} else if (pb.getType() == 2) { // json 扩展
setTip("正在解析播放地址", true, false);
parseThreadPool = Executors.newSingleThreadExecutor();
LinkedHashMap<String, String> 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<String, String> 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<String, HashMap<String, String>> 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<String, String> 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<String, String> webHeaders = new HashMap<>();
try {

@ -0,0 +1,12 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="128dp"
android:height="128dp"
android:viewportWidth="1024"
android:viewportHeight="1024">
<path
android:pathData="M509.39,227.57l-338.73,622.55h677.45l-338.73,-622.55zM559.37,200.38l338.73,622.55c15.02,27.6 4.82,62.14 -22.78,77.16a56.89,56.89 0,0 1,-27.19 6.92L170.67,907.01c-31.42,0 -56.89,-25.47 -56.89,-56.89a56.89,56.89 0,0 1,6.92 -27.19l338.73,-622.55c15.02,-27.6 49.56,-37.8 77.16,-22.78a56.89,56.89 0,0 1,22.78 22.78z"
android:fillColor="#ffffff"/>
<path
android:pathData="M483.82,409.63c-0.09,-4.2 2.91,-7.61 7.31,-7.61h42.26c4.13,0 7.41,3.19 7.31,7.61l-6.02,269.23c-0.09,4.2 -3.66,7.61 -7.52,7.61h-29.81c-4.06,0 -7.42,-3.19 -7.52,-7.61l-6.02,-269.23zM512.26,771.8c-15.71,0 -28.44,-12.73 -28.44,-28.44 0,-15.71 12.73,-28.44 28.44,-28.44 15.71,0 28.44,12.74 28.44,28.44s-12.73,28.44 -28.44,28.44z"
android:fillColor="#ffffff"/>
</vector>

@ -1,18 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/black">
<FrameLayout
android:id="@+id/rootLayout"
<xyz.doikki.videoplayer.player.VideoView
android:id="@+id/mVideoView"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent" />
<ProgressBar
android:id="@+id/play_loading"
android:layout_width="@dimen/vs_50"
android:layout_height="@dimen/vs_50"
android:layout_gravity="center"
android:indeterminateBehavior="repeat"
android:indeterminateDrawable="@drawable/anim_loading"
android:indeterminateOnly="true" />
<xyz.doikki.videoplayer.player.VideoView
android:id="@+id/mVideoView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
<ImageView
android:id="@+id/play_load_error"
android:layout_width="@dimen/vs_50"
android:layout_height="@dimen/vs_50"
android:layout_gravity="center"
android:alpha="0.75"
android:focusable="false"
android:focusableInTouchMode="false"
android:src="@drawable/icon_error"
android:visibility="gone"
tools:visibility="visible" />
<TextView
android:id="@+id/play_load_tip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="@dimen/vs_50"
android:text="1111111111111"
android:textColor="@color/color_CCFFFFFF"
android:textSize="@dimen/ts_22" />
</FrameLayout>

@ -36,6 +36,19 @@
android:textColor="@color/color_CC000000"
android:textSize="@dimen/ts_20" />
<TextView
android:id="@+id/play_next"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/vs_5"
android:layout_marginRight="@dimen/vs_5"
android:background="@drawable/button_dialog_main"
android:focusable="true"
android:padding="@dimen/vs_10"
android:text="下一集"
android:textColor="@android:color/white"
android:textSize="@dimen/ts_20" />
<TextView
android:id="@+id/play_pre"
android:layout_width="wrap_content"
@ -50,7 +63,7 @@
android:textSize="@dimen/ts_20" />
<TextView
android:id="@+id/play_next"
android:id="@+id/play_retry"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/vs_5"
@ -58,7 +71,7 @@
android:background="@drawable/button_dialog_main"
android:focusable="true"
android:padding="@dimen/vs_10"
android:text="下一集"
android:text="重播本集"
android:textColor="@android:color/white"
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" />
</FrameLayout>
Loading…
Cancel
Save