diff --git a/app/src/main/java/com/github/tvbox/osc/ui/activity/LivePlayActivity.java b/app/src/main/java/com/github/tvbox/osc/ui/activity/LivePlayActivity.java index 446298bc..f5d87e2b 100644 --- a/app/src/main/java/com/github/tvbox/osc/ui/activity/LivePlayActivity.java +++ b/app/src/main/java/com/github/tvbox/osc/ui/activity/LivePlayActivity.java @@ -247,6 +247,7 @@ public class LivePlayActivity extends BaseActivity { } }); } else { + showSuccess(); initList(list); } } 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 222a7f6d..93ca76ca 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 @@ -5,6 +5,9 @@ import android.os.Bundle; import android.view.KeyEvent; import android.widget.Toast; +import androidx.lifecycle.Observer; +import androidx.lifecycle.ViewModelProvider; + import com.dueeeke.videocontroller.component.GestureView; import com.dueeeke.videoplayer.player.VideoView; import com.github.tvbox.osc.R; @@ -16,9 +19,11 @@ import com.github.tvbox.osc.player.controller.BoxVodControlView; import com.github.tvbox.osc.ui.dialog.ParseDialog; import com.github.tvbox.osc.util.HawkConfig; import com.github.tvbox.osc.util.PlayerHelper; +import com.github.tvbox.osc.viewmodel.SourceViewModel; import com.orhanobut.hawk.Hawk; import org.greenrobot.eventbus.EventBus; +import org.json.JSONObject; import java.util.Map; @@ -30,6 +35,7 @@ import java.util.Map; public class PlayActivity extends BaseActivity { private VideoView mVideoView; private BoxVideoController controller; + private SourceViewModel sourceViewModel; @Override protected int getLayoutResID() { @@ -39,10 +45,12 @@ public class PlayActivity extends BaseActivity { @Override protected void init() { initView(); + initViewModel(); initData(); } private void initView() { + setLoadSir(findViewById(R.id.rootLayout)); mVideoView = findViewById(R.id.mVideoView); PlayerHelper.updateCfg(mVideoView); // ViewGroup.LayoutParams layoutParams = mVideoView.getLayoutParams(); @@ -96,6 +104,39 @@ public class PlayActivity extends BaseActivity { mVideoView.setVideoController(controller); } + private void initViewModel() { + sourceViewModel = new ViewModelProvider(this).get(SourceViewModel.class); + sourceViewModel.playResult.observe(this, new Observer() { + @Override + public void onChanged(JSONObject object) { + showSuccess(); + if (object != null && object.optString("key", "").equals(parseKey)) { + parseDialog.parse(sourceKey, object, new ParseDialog.ParseCallback() { + @Override + public void success(String playUrl, Map headers) { + if (mVideoView != null) { + mVideoView.release(); + if (headers != null) { + mVideoView.setUrl(playUrl, headers); + } else { + mVideoView.setUrl(playUrl); + } + mVideoView.start(); + } + tryDismissParse(); + } + + @Override + public void fail() { +// PlayActivity.this.finish(); +// tryDismissParse(); + } + }); + } + } + }); + } + private void initData() { Intent intent = getIntent(); if (intent != null && intent.getExtras() != null) { @@ -216,6 +257,9 @@ public class PlayActivity extends BaseActivity { } } + + private volatile String parseKey = null; + public void play() { VodInfo.VodSeries vs = mVodInfo.seriesMap.get(mVodInfo.playFlag).get(mVodInfo.playIndex); EventBus.getDefault().post(new RefreshEvent(RefreshEvent.TYPE_REFRESH, mVodInfo.playIndex)); @@ -233,26 +277,8 @@ public class PlayActivity extends BaseActivity { parseDialog.show(); - parseDialog.parse(sourceKey, mVodInfo.playFlag, vs.url, new ParseDialog.ParseCallback() { - @Override - public void success(String playUrl, Map headers) { - if (mVideoView != null) { - mVideoView.release(); - if (headers != null) { - mVideoView.setUrl(playUrl, headers); - } else { - mVideoView.setUrl(playUrl); - } - mVideoView.start(); - } - tryDismissParse(); - } - - @Override - public void fail() { - PlayActivity.this.finish(); - tryDismissParse(); - } - }); + parseKey = vs.url; + showLoading(); + sourceViewModel.getPlay(sourceKey, mVodInfo.playFlag, vs.url); } } \ No newline at end of file diff --git a/app/src/main/java/com/github/tvbox/osc/ui/activity/ProjectionPlayActivity.java b/app/src/main/java/com/github/tvbox/osc/ui/activity/ProjectionPlayActivity.java index f7137e81..027b7a5c 100644 --- a/app/src/main/java/com/github/tvbox/osc/ui/activity/ProjectionPlayActivity.java +++ b/app/src/main/java/com/github/tvbox/osc/ui/activity/ProjectionPlayActivity.java @@ -113,7 +113,7 @@ public class ProjectionPlayActivity extends BaseActivity { parseDialog.show(); - parseDialog.parse("", "", html, new ParseDialog.ParseCallback() { +/* parseDialog.parse("", "", html, new ParseDialog.ParseCallback() { @Override public void success(String playUrl, Map headers) { controller.boxTVRefreshInfo(playUrl); @@ -130,7 +130,7 @@ public class ProjectionPlayActivity extends BaseActivity { ProjectionPlayActivity.this.finish(); tryDismissParse(); } - }); + });*/ } } diff --git a/app/src/main/java/com/github/tvbox/osc/ui/dialog/ParseDialog.java b/app/src/main/java/com/github/tvbox/osc/ui/dialog/ParseDialog.java index d5d2bb04..3b9be7b8 100644 --- a/app/src/main/java/com/github/tvbox/osc/ui/dialog/ParseDialog.java +++ b/app/src/main/java/com/github/tvbox/osc/ui/dialog/ParseDialog.java @@ -4,11 +4,9 @@ import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; import android.graphics.Color; -import android.net.Uri; import android.net.http.SslError; import android.os.Build; import android.os.Handler; -import android.text.TextUtils; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; @@ -33,7 +31,6 @@ import com.chad.library.adapter.base.BaseQuickAdapter; import com.github.tvbox.osc.R; import com.github.tvbox.osc.api.ApiConfig; import com.github.tvbox.osc.bean.ParseBean; -import com.github.tvbox.osc.bean.SourceBean; import com.github.tvbox.osc.ui.adapter.ParseDialogAdapter; import com.github.tvbox.osc.util.AdBlocker; import com.github.tvbox.osc.util.DefaultConfig; @@ -42,10 +39,14 @@ import com.github.tvbox.osc.util.HawkConfig; import com.github.tvbox.osc.util.LOG; import com.github.tvbox.osc.util.XWalkUtils; import com.lzy.okgo.OkGo; +import com.lzy.okgo.callback.AbsCallback; +import com.lzy.okgo.model.Response; import com.orhanobut.hawk.Hawk; import com.owen.tvrecyclerview.widget.TvRecyclerView; import com.owen.tvrecyclerview.widget.V7GridLayoutManager; +import org.json.JSONException; +import org.json.JSONObject; import org.xwalk.core.XWalkResourceClient; import org.xwalk.core.XWalkSettings; import org.xwalk.core.XWalkUIClient; @@ -56,6 +57,7 @@ import org.xwalk.core.XWalkWebResourceResponse; import java.io.ByteArrayInputStream; import java.util.ArrayList; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; @@ -84,6 +86,7 @@ public class ParseDialog { private Runnable mParseTimeOut = new Runnable() { @Override public void run() { + OkGo.getInstance().cancelTag("json_jx"); Toast.makeText(mContext, "解析超时,请尝试切换解析重试!", Toast.LENGTH_SHORT).show(); } }; @@ -152,15 +155,37 @@ public class ParseDialog { void fail(); } - public void parse(String sourceKey, String flag, String url, ParseCallback callback) { - Uri uir = Uri.parse(url); - String urlPath = uir.getPath(); - String format = DefaultConfig.getFileSuffix(urlPath); - SourceBean sb = ApiConfig.get().getSource(sourceKey); - if (DefaultConfig.isVideoFormat(format)) { - callback.success(url, null); - } else { // 解析咯 - initParse(sourceKey, flag, url, callback); + public void parse(String sourceKey, JSONObject info, ParseCallback callback) { + try { + boolean parse = info.optString("parse", "1").equals("1"); + boolean jx = info.optString("jx", "0").equals("1"); + String playUrl = info.optString("playUrl", ""); + String flag = info.optString("flag"); + String url = info.getString("url"); + HashMap headers = null; + if (info.has("header")) { + try { + JSONObject hds = new JSONObject(info.getString("header")); + Iterator keys = hds.keys(); + while (keys.hasNext()) { + String key = keys.next(); + if (headers == null) { + headers = new HashMap<>(); + } + headers.put(key, hds.getString(key)); + } + } catch (Throwable th) { + + } + } + if (parse || jx) { + boolean userJxList = (playUrl.isEmpty() && ApiConfig.get().getVipParseFlags().contains(flag)) || jx; + initParse(flag, userJxList, playUrl, url, callback); + } else { + callback.success(playUrl + url, headers); + } + } catch (Throwable th) { + callback.fail(); } } @@ -169,7 +194,7 @@ public class ParseDialog { private WebView mSysWebView; private SysWebClient mSysWebClient; - private void initParse(String sourceKey, String flag, String url, ParseCallback callback) { + private void initParse(String flag, boolean userJx, String playUrl, String url, ParseCallback callback) { mParseTip.setText("资源解析中,请稍后"); if (mSysWebView == null && mX5WebView == null) { boolean useSystemWebView = Hawk.get(HawkConfig.PARSE_WEBVIEW, true); @@ -178,29 +203,29 @@ public class ParseDialog { @Override public void success() { initWebView(false); - initParseBean(sourceKey, flag, url, callback); + initParseBean(flag, userJx, playUrl, url, callback); } @Override public void fail() { Toast.makeText(mContext, "XWalkView不兼容,已替换为系统自带WebView", Toast.LENGTH_LONG).show(); initWebView(true); - initParseBean(sourceKey, flag, url, callback); + initParseBean(flag, userJx, playUrl, url, callback); } @Override public void ignore() { Toast.makeText(mContext, "XWalkView运行组件未下载,已替换为系统自带WebView", Toast.LENGTH_LONG).show(); initWebView(true); - initParseBean(sourceKey, flag, url, callback); + initParseBean(flag, userJx, playUrl, url, callback); } }); } else { initWebView(true); - initParseBean(sourceKey, flag, url, callback); + initParseBean(flag, userJx, playUrl, url, callback); } } else { - initParseBean(sourceKey, flag, url, callback); + initParseBean(flag, userJx, playUrl, url, callback); } } @@ -214,29 +239,107 @@ public class ParseDialog { } } - private void loadUrl(String url, ParseCallback callback) { - if (mSysWebClient != null) { - mSysWebClient.setCallback(callback); - } - if (mX5WebClient != null) { - mX5WebClient.setCallback(callback); - } - if (mX5WebView != null) { - mX5WebView.stopLoading(); - mX5WebView.clearCache(true); - mX5WebView.loadUrl(url); - } - if (mSysWebView != null) { - mSysWebView.stopLoading(); - mSysWebView.clearCache(true); - mSysWebView.loadUrl(url); + JSONObject jsonParse(String input, String json) throws JSONException { + JSONObject jsonPlayData = new JSONObject(json); + String url = jsonPlayData.getString("url"); + String msg = jsonPlayData.optString("msg", ""); + if (url.startsWith("//")) { + url = "https:" + url; + } + if (!url.startsWith("http")) { + return null; + } + JSONObject headers = new JSONObject(); + String ua = jsonPlayData.optString("user-agent", ""); + if (ua.trim().length() > 0) { + headers.put("User-Agent", " " + ua); + } + String referer = jsonPlayData.optString("referer", ""); + if (referer.trim().length() > 0) { + headers.put("Referer", " " + referer); + } + JSONObject taskResult = new JSONObject(); + taskResult.put("header", headers); + taskResult.put("url", url); + return taskResult; + } + + private void doJsonJx(String jx, String url, ParseCallback callback) { + OkGo.get(jx + url) + .tag("json_jx") + .execute(new AbsCallback() { + @Override + public String convertResponse(okhttp3.Response response) throws Throwable { + if (response.body() != null) { + return response.body().string(); + } else { + throw new IllegalStateException("网络请求错误"); + } + } + + @Override + public void onSuccess(Response response) { + String json = response.body(); + try { + JSONObject rs = jsonParse(url, json); + HashMap headers = null; + if (rs.has("header")) { + try { + JSONObject hds = rs.getJSONObject("header"); + Iterator keys = hds.keys(); + while (keys.hasNext()) { + String key = keys.next(); + if (headers == null) { + headers = new HashMap<>(); + } + headers.put(key, hds.getString(key)); + } + } catch (Throwable th) { + + } + } + callback.success(rs.getString("url"), headers); + } catch (JSONException e) { + e.printStackTrace(); + callback.fail(); + } + } + + @Override + public void onError(Response response) { + super.onError(response); + callback.fail(); + } + }); + } + + private void loadUrl(ParseBean pb, String url, ParseCallback callback) { + if (pb == null || pb.getType() == 0) { + if (mSysWebClient != null) { + mSysWebClient.setCallback(callback); + } + if (mX5WebClient != null) { + mX5WebClient.setCallback(callback); + } + if (mX5WebView != null) { + mX5WebView.stopLoading(); + mX5WebView.clearCache(true); + mX5WebView.loadUrl(url); + } + if (mSysWebView != null) { + mSysWebView.stopLoading(); + mSysWebView.clearCache(true); + mSysWebView.loadUrl(url); + } + } else if (pb.getType() == 1) { // json 解析 + doJsonJx(pb.getUrl(), url, callback); } mHandler.removeCallbacks(mParseTimeOut); mHandler.postDelayed(mGridFocus, 200); mHandler.postDelayed(mParseTimeOut, 30000); } - private void initParseBean(String sourceKey, String flag, final String url, ParseCallback callback) { + private void initParseBean(String flag, boolean userJx, String playUrl, final String url, ParseCallback callback) { if (mGridView == null) { mGridView = findViewById(R.id.mGridView); parseAdapter = new ParseDialogAdapter(); @@ -253,7 +356,7 @@ public class ParseDialog { ApiConfig.get().setDefaultParse(parseBean); parseAdapter.notifyItemChanged(position); loadFound = false; - loadUrl(parseBean.getUrl() + url, callback); + loadUrl(parseBean, url, callback); } }); mGridView.setOnInBorderKeyEventListener(new TvRecyclerView.OnInBorderKeyEventListener() { @@ -264,30 +367,30 @@ public class ParseDialog { }); } int focusParseIdx = 0; - SourceBean sb = ApiConfig.get().getSource(sourceKey); String parseUrl = ""; - if (ApiConfig.get().getVipParseFlags().contains(flag) || TextUtils.isEmpty(flag)) { + ParseBean parseBean = null; + if (userJx) { parseBeans.addAll(ApiConfig.get().getParseBeanList()); - ParseBean parseBean = ApiConfig.get().getDefaultParse(); + parseBean = ApiConfig.get().getDefaultParse(); parseUrl = parseBean.getUrl(); focusParseIdx = parseBeans.indexOf(parseBean); } else { - parseUrl = sb == null ? "" : sb.getPlayerUrl(); + parseUrl = playUrl; focusParseIdx = 0; } loadFound = false; parseAdapter.setNewData(parseBeans); mGridView.setSelection(focusParseIdx); - final String fullParseUrl = parseUrl + url; if (parseBeans.size() > 0) { + ParseBean finalParseBean = parseBean; mHandler.postDelayed(new Runnable() { @Override public void run() { - loadUrl(fullParseUrl, callback); + loadUrl(finalParseBean, url, callback); } }, 3000); } else { - loadUrl(fullParseUrl, callback); + loadUrl(null, parseUrl + url, callback); } } diff --git a/app/src/main/java/com/github/tvbox/osc/util/DefaultConfig.java b/app/src/main/java/com/github/tvbox/osc/util/DefaultConfig.java index 96d61932..dfe06c45 100644 --- a/app/src/main/java/com/github/tvbox/osc/util/DefaultConfig.java +++ b/app/src/main/java/com/github/tvbox/osc/util/DefaultConfig.java @@ -14,11 +14,10 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.HashMap; -import java.util.Iterator; import java.util.List; +import java.util.regex.Pattern; /** * @author pj567 @@ -96,30 +95,22 @@ public class DefaultConfig { return start > -1 ? fileName.substring(0, start) : fileName; } - public static boolean isVideoFormat(String urlOri) { - String url = urlOri.toLowerCase(); + + private static final Pattern snifferMatch = Pattern.compile("http((?!http).){26,}?\\.(m3u8|mp4)\\?.*|http((?!http).){26,}\\.(m3u8|mp4)|http((?!http).){26,}?/m3u8\\?pt=m3u8.*|http((?!http).)*?default\\.ixigua\\.com/.*|http((?!http).)*?cdn-tos[^\\?]*|http((?!http).)*?/obj/tos[^\\?]*|http.*?/player/m3u8play\\.php\\?url=.*|http.*?/player/.*?[pP]lay\\.php\\?url=.*|http.*?/playlist/m3u8/\\?vid=.*|http.*?\\.php\\?type=m3u8&.*|http.*?/download.aspx\\?.*|http.*?/api/up_api.php\\?.*|https.*?\\.66yk\\.cn.*|http((?!http).)*?netease\\.com/file/.*"); + + public static boolean isVideoFormat(String url) { if (url.contains("=http") || url.contains("=https") || url.contains("=https%3a%2f") || url.contains("=http%3a%2f")) { return false; } - Iterator keys = videoFormatList.keySet().iterator(); - while (keys.hasNext()) { - String format = keys.next(); - if (url.contains(format)) { - LOG.i("isVideoFormat url:" + urlOri); - return true; + if (snifferMatch.matcher(url).find()) { + if (url.contains("cdn-tos") && (url.contains(".js") || url.contains(".css"))) { + return false; } + return true; } return false; } - private static final HashMap videoFormatList = new HashMap>() {{ - put(".m3u8", Arrays.asList("application/octet-stream", "application/vnd.apple.mpegurl", "application/mpegurl", "application/x-mpegurl", "audio/mpegurl", "audio/x-mpegurl")); - put(".mp4", Arrays.asList("video/mp4", "application/mp4", "video/h264")); - put(".flv", Arrays.asList("video/x-flv")); - put(".f4v", Arrays.asList("video/x-f4v")); - put(".mpeg", Arrays.asList("video/vnd.mpegurl")); - }}; - public static String safeJsonString(JsonObject obj, String key, String defaultVal) { try { diff --git a/app/src/main/java/com/github/tvbox/osc/viewmodel/SourceViewModel.java b/app/src/main/java/com/github/tvbox/osc/viewmodel/SourceViewModel.java index f68b2202..ea5841ef 100644 --- a/app/src/main/java/com/github/tvbox/osc/viewmodel/SourceViewModel.java +++ b/app/src/main/java/com/github/tvbox/osc/viewmodel/SourceViewModel.java @@ -12,6 +12,7 @@ import com.github.tvbox.osc.bean.AbsXml; import com.github.tvbox.osc.bean.Movie; import com.github.tvbox.osc.bean.SourceBean; import com.github.tvbox.osc.event.RefreshEvent; +import com.github.tvbox.osc.util.DefaultConfig; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import com.lzy.okgo.OkGo; @@ -21,6 +22,7 @@ import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.io.xml.DomDriver; import org.greenrobot.eventbus.EventBus; +import org.json.JSONObject; import java.util.ArrayList; import java.util.HashMap; @@ -39,6 +41,7 @@ public class SourceViewModel extends ViewModel { public MutableLiveData searchResult; public MutableLiveData quickSearchResult; public MutableLiveData detailResult; + public MutableLiveData playResult; public SourceViewModel() { sortResult = new MutableLiveData<>(); @@ -46,6 +49,7 @@ public class SourceViewModel extends ViewModel { searchResult = new MutableLiveData<>(); quickSearchResult = new MutableLiveData<>(); detailResult = new MutableLiveData<>(); + playResult = new MutableLiveData<>(); } public static final ExecutorService spThreadPool = Executors.newFixedThreadPool(3); @@ -295,6 +299,51 @@ public class SourceViewModel extends ViewModel { } } + public void getPlay(String sourceKey, String playFlag, String url) { + SourceBean sourceBean = ApiConfig.get().getSource(sourceKey); + int type = sourceBean.getType(); + if (type == 3) { + spThreadPool.execute(new Runnable() { + @Override + public void run() { + Spider sp = ApiConfig.get().getCSP(sourceBean); + String json = sp.playerContent(playFlag, url, ApiConfig.get().getVipParseFlags()); + try { + JSONObject result = new JSONObject(json); + result.put("key", url); + if (!result.has("flag")) + result.put("flag", playFlag); + playResult.postValue(result); + } catch (Throwable th) { + th.printStackTrace(); + playResult.postValue(null); + } + } + }); + } else if (type == 0 || type == 1) { + JSONObject result = new JSONObject(); + try { + result.put("key", url); + String playUrl = sourceBean.getPlayerUrl().trim(); + if (DefaultConfig.isVideoFormat(url)) { + result.put("parse", 0); + result.put("url", url); + } else { + result.put("parse", 1); + result.put("url", url); + } + result.put("playUrl", playUrl); + result.put("flag", playFlag); + playResult.postValue(result); + } catch (Throwable th) { + th.printStackTrace(); + playResult.postValue(null); + } + } else { + quickSearchResult.postValue(null); + } + } + private void sortJson(MutableLiveData result, String json) { try { AbsSortJson sortJson = new Gson().fromJson(json, new TypeToken() { diff --git a/app/src/main/res/layout/activity_play.xml b/app/src/main/res/layout/activity_play.xml index 03bb8fa5..184cf3f8 100644 --- a/app/src/main/res/layout/activity_play.xml +++ b/app/src/main/res/layout/activity_play.xml @@ -1,5 +1,5 @@ -