From 3048407fea1e6579baf7861989da39bc0fb346fa Mon Sep 17 00:00:00 2001 From: FongMi Date: Sat, 11 Feb 2023 22:29:41 +0800 Subject: [PATCH] [mobile] support detail - part 2 --- app/src/main/assets/parse.html | 23 +++ .../java/com/fongmi/android/tv/Constant.java | 6 +- .../android/tv/player/parse/ParseJob.java | 178 ++++++++++++++++++ 3 files changed, 202 insertions(+), 5 deletions(-) create mode 100644 app/src/main/assets/parse.html create mode 100644 app/src/main/java/com/fongmi/android/tv/player/parse/ParseJob.java diff --git a/app/src/main/assets/parse.html b/app/src/main/assets/parse.html new file mode 100644 index 000000000..5550ce890 --- /dev/null +++ b/app/src/main/assets/parse.html @@ -0,0 +1,23 @@ + + + + + 解析 + + + + + + + + + \ No newline at end of file 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 39c0c4297..b5b52ab98 100644 --- a/app/src/main/java/com/fongmi/android/tv/Constant.java +++ b/app/src/main/java/com/fongmi/android/tv/Constant.java @@ -14,13 +14,9 @@ public class Constant { //播放超時時間 public static final int TIMEOUT_PLAY = 15 * 1000; //解析預設時間 - public static final int TIMEOUT_PARSE_DEF = 5 * 1000; + public static final int TIMEOUT_PARSE_DEF = 15 * 1000; //嗅探超時時間 public static final int TIMEOUT_PARSE_WEB = 15 * 1000; - //解析超時時間 - public static final int TIMEOUT_PARSE_JSON = 15 * 1000; - //聚合超時時間 - public static final int TIMEOUT_PARSE_MIX = 15 * 1000; //網路超時時間 public static final int TIMEOUT_HTTP = 30 * 1000; //代理超時時間 diff --git a/app/src/main/java/com/fongmi/android/tv/player/parse/ParseJob.java b/app/src/main/java/com/fongmi/android/tv/player/parse/ParseJob.java new file mode 100644 index 000000000..17f15e03b --- /dev/null +++ b/app/src/main/java/com/fongmi/android/tv/player/parse/ParseJob.java @@ -0,0 +1,178 @@ +package com.fongmi.android.tv.player.parse; + +import android.text.TextUtils; + +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.Parse; +import com.fongmi.android.tv.bean.Result; +import com.fongmi.android.tv.net.OkHttp; +import com.fongmi.android.tv.server.Server; +import com.fongmi.android.tv.ui.custom.CustomWebView; +import com.fongmi.android.tv.utils.Json; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import okhttp3.Headers; +import okhttp3.Response; + +public class ParseJob { + + private ExecutorService executor; + private ExecutorService infinite; + private CustomWebView webView; + private Callback callback; + private Parse parse; + + public static ParseJob create(Callback callback) { + return new ParseJob(callback); + } + + public ParseJob(Callback callback) { + this.executor = Executors.newFixedThreadPool(2); + this.infinite = Executors.newCachedThreadPool(); + this.callback = callback; + } + + public ParseJob start(Result result, boolean useParse) { + setParse(result, useParse); + execute(result); + return this; + } + + private void setParse(Result result, boolean useParse) { + if (useParse) parse = ApiConfig.get().getParse(); + else if (result.getPlayUrl().startsWith("json:")) parse = Parse.get(1, result.getPlayUrl().substring(5)); + else if (result.getPlayUrl().startsWith("parse:")) parse = ApiConfig.get().getParse(result.getPlayUrl().substring(6)); + if (parse == null) parse = Parse.get(0, result.getPlayUrl(), result.getHeader()); + } + + private void execute(Result result) { + executor.execute(() -> { + try { + executor.submit(getTask(result)).get(Constant.TIMEOUT_PARSE_DEF, TimeUnit.MILLISECONDS); + } catch (Throwable e) { + onParseError(); + } + }); + } + + private Runnable getTask(Result result) { + return () -> { + try { + doInBackground(result.getKey(), result.getUrl(), result.getFlag()); + } catch (Exception e) { + onParseError(); + } + }; + } + + private void doInBackground(String key, String webUrl, String flag) throws Exception { + switch (parse.getType()) { + case 0: //嗅探 + App.post(() -> startWeb(key, parse.getUrl() + webUrl, parse.getHeaders(), callback)); + break; + case 1: //Json + jsonParse(parse, webUrl, false); + break; + case 3: //聚合 + mixJson(webUrl, flag); + mixWeb(webUrl, flag); + break; + } + } + + private void jsonParse(Parse item, String webUrl, boolean strict) throws Exception { + Response response = OkHttp.newCall(item.getUrl() + webUrl, Headers.of(item.getHeaders())).execute(); + JsonObject object = JsonParser.parseString(response.body().string()).getAsJsonObject(); + object = object.has("data") ? object.getAsJsonObject("data") : object; + if (strict) checkResult(item, getHeader(object), Json.safeString(object, "url")); + else checkResult(getHeader(object), Json.safeString(object, "url")); + } + + private void mixJson(String webUrl, String flag) { + List items = ApiConfig.get().getParses(1, flag); + for (Parse item : items) infinite.execute(() -> jsonParse(item, webUrl)); + } + + private void mixWeb(String webUrl, String flag) { + StringBuilder sb = new StringBuilder(); + List items = ApiConfig.get().getParses(0, flag); + for (Parse item : items) sb.append(item.getUrl()).append(";"); + if (sb.length() > 0) App.post(() -> startWeb(Server.getParse(sb.toString(), webUrl), callback)); + } + + private void jsonParse(Parse item, String webUrl) { + try { + jsonParse(item, webUrl, true); + } catch (Exception ignored) { + } + } + + private void checkResult(HashMap headers, String url) { + if (TextUtils.isEmpty(url)) onParseError(); + else onParseSuccess(headers, url, ""); + } + + private void checkResult(Parse item, HashMap headers, String url) throws Exception { + int code = OkHttp.newCall(url, Headers.of(headers)).execute().code(); + if (code == 200) onParseSuccess(headers, url, item.getName()); + } + + private void startWeb(String url, Callback callback) { + startWeb(url, new HashMap<>(), callback); + } + + private void startWeb(String url, Map headers, Callback callback) { + startWeb("", url, headers, callback); + } + + private void startWeb(String key, String url, Map headers, Callback callback) { + webView = CustomWebView.create(App.get()).start(key, url, headers, callback); + } + + private HashMap getHeader(JsonObject object) { + HashMap headers = new HashMap<>(); + for (String key : object.keySet()) if (key.equalsIgnoreCase("user-agent") || key.equalsIgnoreCase("referer")) headers.put(key, object.get(key).getAsString()); + return headers; + } + + 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 stop() { + if (executor != null) executor.shutdownNow(); + if (infinite != null) infinite.shutdownNow(); + if (webView != null) webView.stop(false); + infinite = null; + executor = null; + callback = null; + webView = null; + } + + public interface Callback { + + void onParseSuccess(Map headers, String url, String from); + + void onParseError(); + } +} \ No newline at end of file