diff --git a/.gitignore b/.gitignore index f96d801b2..e39b5d594 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ .gradle .idea *build +*.json +*.jks /local.properties \ No newline at end of file diff --git a/app/src/main/java/com/fongmi/bear/player/Player.java b/app/src/main/java/com/fongmi/bear/player/Player.java index c4ece6ad9..1a9624bf5 100644 --- a/app/src/main/java/com/fongmi/bear/player/Player.java +++ b/app/src/main/java/com/fongmi/bear/player/Player.java @@ -1,6 +1,9 @@ package com.fongmi.bear.player; +import android.app.Activity; + import com.fongmi.bear.App; +import com.fongmi.bear.ui.custom.CustomWebView; import com.google.android.exoplayer2.ExoPlayer; import com.google.gson.JsonObject; import com.google.gson.JsonParser; @@ -10,6 +13,8 @@ import java.util.HashMap; public class Player implements com.google.android.exoplayer2.Player.Listener { private final ExoPlayer exoPlayer; + private CustomWebView webView; + private Activity activity; private Callback callback; private static class Loader { @@ -25,8 +30,9 @@ public class Player implements com.google.android.exoplayer2.Player.Listener { exoPlayer.addListener(this); } - public Player callback(Callback callback) { - this.callback = callback; + public Player callback(Activity activity) { + this.callback = (Callback) activity; + this.activity = activity; return this; } @@ -36,14 +42,33 @@ public class Player implements com.google.android.exoplayer2.Player.Listener { public void setMediaSource(JsonObject object) { HashMap headers = new HashMap<>(); + String parse = object.get("parse").getAsString(); String url = object.get("url").getAsString(); if (object.has("header")) { JsonObject header = JsonParser.parseString(object.get("header").getAsString()).getAsJsonObject(); for (String key : header.keySet()) headers.put(key, header.get(key).getAsString()); } - exoPlayer.setMediaSource(ExoUtil.getSource(headers, url)); - exoPlayer.prepare(); - exoPlayer.play(); + if (parse.equals("1")) { + loadWebView(url); + } else { + setMediaSource(headers, url); + } + } + + private void loadWebView(String url) { + activity.runOnUiThread(() -> { + if (webView != null) webView.destroy(); + webView = new CustomWebView(App.get()).init(); + webView.loadUrl(url); + }); + } + + public void setMediaSource(HashMap headers, String url) { + activity.runOnUiThread(() -> { + exoPlayer.setMediaSource(ExoUtil.getSource(headers, url)); + exoPlayer.prepare(); + exoPlayer.play(); + }); } public void pause() { diff --git a/app/src/main/java/com/fongmi/bear/server/Server.java b/app/src/main/java/com/fongmi/bear/server/Server.java new file mode 100644 index 000000000..6eedb67d1 --- /dev/null +++ b/app/src/main/java/com/fongmi/bear/server/Server.java @@ -0,0 +1,12 @@ +package com.fongmi.bear.server; + +import fi.iki.elonen.NanoHTTPD; + +public class Server extends NanoHTTPD { + + public static int port = 9978; + + public Server() { + super(port); + } +} diff --git a/app/src/main/java/com/fongmi/bear/ui/custom/CustomWebView.java b/app/src/main/java/com/fongmi/bear/ui/custom/CustomWebView.java new file mode 100644 index 000000000..e7fb794b0 --- /dev/null +++ b/app/src/main/java/com/fongmi/bear/ui/custom/CustomWebView.java @@ -0,0 +1,89 @@ +package com.fongmi.bear.ui.custom; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.net.http.SslError; +import android.os.Handler; +import android.os.Looper; +import android.util.AttributeSet; +import android.webkit.SslErrorHandler; +import android.webkit.WebResourceRequest; +import android.webkit.WebResourceResponse; +import android.webkit.WebSettings; +import android.webkit.WebView; +import android.webkit.WebViewClient; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.fongmi.bear.player.Player; +import com.fongmi.bear.utils.Utils; + +import java.util.HashMap; +import java.util.Map; + +public class CustomWebView extends WebView { + + public CustomWebView(@NonNull Context context) { + super(context); + } + + public CustomWebView(@NonNull Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + } + + public CustomWebView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + @SuppressLint("SetJavaScriptEnabled") + public CustomWebView init() { + getSettings().setUseWideViewPort(true); + getSettings().setDatabaseEnabled(true); + getSettings().setDomStorageEnabled(true); + getSettings().setJavaScriptEnabled(true); + getSettings().setBlockNetworkImage(true); + getSettings().setLoadWithOverviewMode(true); + getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE); + getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW); + setWebViewClient(webViewClient()); + return this; + } + + private WebViewClient webViewClient() { + return new WebViewClient() { + @Override + public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) { + handler.proceed(); + } + + @Override + public boolean shouldOverrideUrlLoading(WebView view, String url) { + return false; + } + + @Nullable + @Override + public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) { + String url = request.getUrl().toString(); + HashMap headers = new HashMap<>(); + Map hds = request.getRequestHeaders(); + for (String k : hds.keySet()) { + if (k.equalsIgnoreCase("user-agent") || k.equalsIgnoreCase("referer") || k.equalsIgnoreCase("origin")) { + headers.put(k, hds.get(k)); + } + } + if (Utils.isVideoFormat(url)) { + if (headers.isEmpty()) { + new Handler(Looper.getMainLooper()).post(() -> destroy()); + Player.get().setMediaSource(headers, url); + } else { + new Handler(Looper.getMainLooper()).post(() -> destroy()); + Player.get().setMediaSource(new HashMap<>(), url); + } + } + return super.shouldInterceptRequest(view, request); + } + }; + } +} diff --git a/app/src/main/java/com/fongmi/bear/utils/Utils.java b/app/src/main/java/com/fongmi/bear/utils/Utils.java index 26cddad4b..ffe663d4c 100644 --- a/app/src/main/java/com/fongmi/bear/utils/Utils.java +++ b/app/src/main/java/com/fongmi/bear/utils/Utils.java @@ -14,8 +14,12 @@ import com.fongmi.bear.App; import com.fongmi.bear.R; import com.google.android.exoplayer2.util.Util; +import java.util.regex.Pattern; + public class Utils { + 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 hasEvent(KeyEvent event) { return isArrowKey(event) || isBackKey(event) || isMenuKey(event) || isDigitKey(event) || event.isLongPress(); } @@ -82,4 +86,10 @@ public class Utils { public static String getUserAgent() { return Util.getUserAgent(App.get(), App.get().getPackageName().concat(".").concat(getUUID())); } + + 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; + if (snifferMatch.matcher(url).find()) return !url.contains("cdn-tos") || (!url.contains(".js") && !url.contains(".css")); + return false; + } }