diff --git a/app/build.gradle b/app/build.gradle index 23755f056..57e7908c7 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -14,7 +14,7 @@ android { //noinspection ExpiredTargetSdkVersion targetSdk 28 versionCode 240 - versionName "2.4.0" + versionName "0627" javaCompileOptions { annotationProcessorOptions { arguments = ["room.schemaLocation": "$projectDir/schemas".toString()] diff --git a/app/src/leanback/java/com/fongmi/android/tv/ui/activity/VideoActivity.java b/app/src/leanback/java/com/fongmi/android/tv/ui/activity/VideoActivity.java index cc87c67a7..6e8ee4d3c 100644 --- a/app/src/leanback/java/com/fongmi/android/tv/ui/activity/VideoActivity.java +++ b/app/src/leanback/java/com/fongmi/android/tv/ui/activity/VideoActivity.java @@ -736,7 +736,6 @@ public class VideoActivity extends BaseActivity implements CustomKeyDownVod.List private void setQualityActivated(Result result) { try { - result.setUrl(Source.get().fetch(result)); mPlayers.start(result, isUseParse(), getSite().isChangeable() ? getSite().getTimeout() : -1); mBinding.danmaku.hide(); } catch (Exception e) { diff --git a/app/src/leanback/java/com/fongmi/android/tv/ui/base/BaseActivity.java b/app/src/leanback/java/com/fongmi/android/tv/ui/base/BaseActivity.java index f17c584ed..ab1e9a7c0 100644 --- a/app/src/leanback/java/com/fongmi/android/tv/ui/base/BaseActivity.java +++ b/app/src/leanback/java/com/fongmi/android/tv/ui/base/BaseActivity.java @@ -3,6 +3,7 @@ package com.fongmi.android.tv.ui.base; import android.app.Activity; import android.content.res.Configuration; import android.content.res.Resources; +import android.graphics.drawable.Drawable; import android.os.Bundle; import android.view.View; @@ -15,7 +16,6 @@ import androidx.viewbinding.ViewBinding; import com.fongmi.android.tv.R; import com.fongmi.android.tv.Setting; -import com.fongmi.android.tv.api.config.WallConfig; import com.fongmi.android.tv.event.RefreshEvent; import com.fongmi.android.tv.utils.FileUtil; import com.fongmi.android.tv.utils.ResUtil; diff --git a/app/src/main/java/com/fongmi/android/tv/bean/Drm.java b/app/src/main/java/com/fongmi/android/tv/bean/Drm.java index 01f530d9a..58f847c66 100644 --- a/app/src/main/java/com/fongmi/android/tv/bean/Drm.java +++ b/app/src/main/java/com/fongmi/android/tv/bean/Drm.java @@ -44,7 +44,7 @@ public class Drm { private String getUri() { if (getKey().startsWith("http")) return getKey(); - return Server.get().getAddress("license/") + Util.base64(getKey()); + return Server.get().getAddress("license/") + Util.base64(getKey(), Util.URL_SAFE); } public MediaItem.DrmConfiguration get() { diff --git a/app/src/main/java/com/fongmi/android/tv/bean/Parse.java b/app/src/main/java/com/fongmi/android/tv/bean/Parse.java index 07b424aa0..10fa7757c 100644 --- a/app/src/main/java/com/fongmi/android/tv/bean/Parse.java +++ b/app/src/main/java/com/fongmi/android/tv/bean/Parse.java @@ -1,7 +1,6 @@ package com.fongmi.android.tv.bean; import android.text.TextUtils; -import android.util.Base64; import androidx.annotation.NonNull; @@ -128,7 +127,7 @@ public class Parse { public String extUrl() { int index = getUrl().indexOf("?"); if (getExt().isEmpty() || index == -1) return getUrl(); - return getUrl().substring(0, index + 1) + "cat_ext=" + Util.base64(getExt().toString(), Base64.DEFAULT | Base64.URL_SAFE | Base64.NO_WRAP) + "&" + getUrl().substring(index + 1); + return getUrl().substring(0, index + 1) + "cat_ext=" + Util.base64(getExt().toString(), Util.URL_SAFE) + "&" + getUrl().substring(index + 1); } public HashMap mixMap() { diff --git a/app/src/main/java/com/fongmi/android/tv/model/SiteViewModel.java b/app/src/main/java/com/fongmi/android/tv/model/SiteViewModel.java index ad06e757c..9882ed659 100644 --- a/app/src/main/java/com/fongmi/android/tv/model/SiteViewModel.java +++ b/app/src/main/java/com/fongmi/android/tv/model/SiteViewModel.java @@ -112,7 +112,7 @@ public class SiteViewModel extends ViewModel { } else { ArrayMap params = new ArrayMap<>(); if (site.getType() == 1 && !extend.isEmpty()) params.put("f", App.gson().toJson(extend)); - else if (site.getType() == 4) params.put("ext", Util.base64(App.gson().toJson(extend))); + if (site.getType() == 4) params.put("ext", Util.base64(App.gson().toJson(extend), Util.URL_SAFE)); params.put("ac", site.getType() == 0 ? "videolist" : "detail"); params.put("t", tid); params.put("pg", page); @@ -157,7 +157,7 @@ public class SiteViewModel extends ViewModel { }); } - public void executePlayer(MutableLiveData data, String key, String flag, String id) { + private void executePlayer(MutableLiveData data, String key, String flag, String id) { execute(data, () -> { Source.get().stop(); Site site = VodConfig.get().getSite(key); @@ -199,6 +199,7 @@ public class SiteViewModel extends ViewModel { result.setFlag(flag); result.setHeader(site.getHeader()); result.setPlayUrl(site.getPlayUrl()); + result.setUrl(Source.get().fetch(result)); result.setParse(Sniffer.isVideoFormat(url.v()) && result.getPlayUrl().isEmpty() ? 0 : 1); SpiderDebug.log(result.toString()); return result; diff --git a/app/src/main/java/com/fongmi/android/tv/player/Source.java b/app/src/main/java/com/fongmi/android/tv/player/Source.java index 61477f573..1edc8d659 100644 --- a/app/src/main/java/com/fongmi/android/tv/player/Source.java +++ b/app/src/main/java/com/fongmi/android/tv/player/Source.java @@ -10,7 +10,6 @@ import com.fongmi.android.tv.player.extractor.TVBus; import com.fongmi.android.tv.player.extractor.Thunder; import com.fongmi.android.tv.player.extractor.Video; import com.fongmi.android.tv.player.extractor.Youtube; -import com.fongmi.android.tv.player.extractor.ZLive; import com.fongmi.android.tv.utils.UrlUtil; import java.util.ArrayList; @@ -38,7 +37,6 @@ public class Source { extractors.add(new TVBus()); extractors.add(new Video()); extractors.add(new Youtube()); - extractors.add(new ZLive()); } private Extractor getExtractor(String url) { diff --git a/app/src/main/java/com/fongmi/android/tv/server/Nano.java b/app/src/main/java/com/fongmi/android/tv/server/Nano.java index ecdf5a13c..492f81b03 100644 --- a/app/src/main/java/com/fongmi/android/tv/server/Nano.java +++ b/app/src/main/java/com/fongmi/android/tv/server/Nano.java @@ -70,7 +70,7 @@ public class Nano extends NanoHTTPD { if (url.startsWith("/proxy")) return proxy(session); if (url.startsWith("/tvbus")) return success(LiveConfig.getResp()); if (url.startsWith("/device")) return success(Device.get().toString()); - if (url.startsWith("/license")) return success(Util.decode(url.substring(9))); + if (url.startsWith("/license")) return success(new String(Util.decode(url.substring(9), Util.URL_SAFE))); for (Process process : process) if (process.isRequest(session, url)) return process.doResponse(session, url, files); return getAssets(url.substring(1)); } @@ -98,7 +98,10 @@ public class Nano extends NanoHTTPD { Map params = session.getParms(); params.putAll(session.getHeaders()); Object[] rs = VodConfig.get().proxyLocal(params); - return rs[0] instanceof Response ? (Response) rs[0] : newChunkedResponse(Response.Status.lookup((Integer) rs[0]), (String) rs[1], (InputStream) rs[2]); + if (rs[0] instanceof Response) return (Response) rs[0]; + Response response = newChunkedResponse(Response.Status.lookup((Integer) rs[0]), (String) rs[1], (InputStream) rs[2]); + if (rs.length > 3 && rs[3] != null) for (Map.Entry entry : ((Map) rs[3]).entrySet()) response.addHeader(entry.getKey(), entry.getValue()); + return response; } catch (Exception e) { return error(e.getMessage()); } diff --git a/app/src/main/java/com/fongmi/android/tv/utils/Sniffer.java b/app/src/main/java/com/fongmi/android/tv/utils/Sniffer.java index 42a36e6a0..73b4cb6c4 100644 --- a/app/src/main/java/com/fongmi/android/tv/utils/Sniffer.java +++ b/app/src/main/java/com/fongmi/android/tv/utils/Sniffer.java @@ -17,7 +17,7 @@ public class Sniffer { public static final Pattern CLICKER = Pattern.compile("\\[a=cr:(\\{.*?\\})\\/](.*?)\\[\\/a]"); public static final Pattern AI_PUSH = Pattern.compile("(http|https|rtmp|rtsp|smb|ftp|thunder|magnet|ed2k|mitv|tvbox-xg|jianpian|video):[^\\s]+", Pattern.MULTILINE); - public static final Pattern SNIFFER = Pattern.compile("http((?!http).){12,}?\\.(m3u8|mp4|mkv|flv|mp3|m4a|aac)\\?.*|http((?!http).){12,}\\.(m3u8|mp4|mkv|flv|mp3|m4a|aac)|http((?!http).)*?video/tos*|http((?!http).)*?obj/tos*"); + public static final Pattern SNIFFER = Pattern.compile("http((?!http).){12,}?\\.(m3u8|mp4|mkv|flv|mp3|m4a|aac|mpd)\\?.*|http((?!http).){12,}\\.(m3u8|mp4|mkv|flv|mp3|m4a|aac|mpd)|http((?!http).)*?video/tos*|http((?!http).)*?obj/tos*"); public static final Pattern THUNDER = Pattern.compile("(magnet|thunder|ed2k):.*"); public static boolean isThunder(String url) { diff --git a/app/src/mobile/java/com/fongmi/android/tv/ui/activity/VideoActivity.java b/app/src/mobile/java/com/fongmi/android/tv/ui/activity/VideoActivity.java index 5773e1096..d60f780f5 100644 --- a/app/src/mobile/java/com/fongmi/android/tv/ui/activity/VideoActivity.java +++ b/app/src/mobile/java/com/fongmi/android/tv/ui/activity/VideoActivity.java @@ -422,6 +422,14 @@ public class VideoActivity extends BaseActivity implements Clock.Callback, Custo mBinding.video.addOnLayoutChangeListener((view, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> mPiP.update(getActivity(), view)); } + private void setVideoView(boolean isInPictureInPictureMode) { + if (isInPictureInPictureMode) { + mBinding.video.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT)); + } else { + mBinding.video.setLayoutParams(mFrameParams); + } + } + private void setSubtitleView() { setSubtitle(Setting.getSubtitle()); getExo().getSubtitleView().setStyle(ExoUtil.getCaptionStyle()); @@ -657,7 +665,6 @@ public class VideoActivity extends BaseActivity implements Clock.Callback, Custo @Override public void onItemClick(Result result) { try { - result.setUrl(Source.get().fetch(result)); mPlayers.start(result, isUseParse(), getSite().isChangeable() ? getSite().getTimeout() : -1); mBinding.danmaku.hide(); } catch (Exception e) { @@ -1716,17 +1723,16 @@ public class VideoActivity extends BaseActivity implements Clock.Callback, Custo @Override public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) { super.onPictureInPictureModeChanged(isInPictureInPictureMode); + if (!isFullscreen()) setVideoView(isInPictureInPictureMode); if (isInPictureInPictureMode) { PlaybackService.start(mPlayers); mBinding.danmaku.hide(); - enterFullscreen(); setSubtitle(10); hideControl(); hideSheet(); } else { showDanmu(); setForeground(true); - exitFullscreen(); PlaybackService.stop(); setSubtitle(Setting.getSubtitle()); if (isStop()) finish(); diff --git a/catvod/src/main/java/com/github/catvod/utils/Json.java b/catvod/src/main/java/com/github/catvod/utils/Json.java index 3eb81f35d..20c93cbeb 100644 --- a/catvod/src/main/java/com/github/catvod/utils/Json.java +++ b/catvod/src/main/java/com/github/catvod/utils/Json.java @@ -1,5 +1,7 @@ package com.github.catvod.utils; +import android.text.TextUtils; + import androidx.collection.ArrayMap; import com.google.gson.JsonElement; @@ -69,6 +71,10 @@ public class Json { } } + public static Map toMap(String json) { + return TextUtils.isEmpty(json) ? null : toMap(parse(json)); + } + public static Map toMap(JsonElement element) { Map map = new HashMap<>(); JsonObject object = safeObject(element); diff --git a/catvod/src/main/java/com/github/catvod/utils/Util.java b/catvod/src/main/java/com/github/catvod/utils/Util.java index 260794c3b..a72c301fc 100644 --- a/catvod/src/main/java/com/github/catvod/utils/Util.java +++ b/catvod/src/main/java/com/github/catvod/utils/Util.java @@ -25,25 +25,30 @@ import java.util.Enumeration; public class Util { public static final String CHROME = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36"; + public static final int URL_SAFE = Base64.DEFAULT | Base64.URL_SAFE | Base64.NO_WRAP; public static String base64(String s) { - return base64(s, Base64.URL_SAFE | Base64.NO_PADDING); + return base64(s.getBytes()); } - public static String base64(String s, int flags) { - return base64(s.getBytes(), flags); + public static String base64(byte[] bytes) { + return base64(bytes, Base64.DEFAULT | Base64.NO_WRAP); } - public static String base64(byte[] bytes) { - return base64(bytes, Base64.DEFAULT); + public static String base64(String s, int flags) { + return base64(s.getBytes(), flags); } public static String base64(byte[] bytes, int flags) { return Base64.encodeToString(bytes, flags); } - public static String decode(String s) { - return new String(Base64.decode(s, Base64.URL_SAFE | Base64.NO_PADDING)); + public static byte[] decode(String s) { + return decode(s, Base64.DEFAULT | Base64.NO_WRAP); + } + + public static byte[] decode(String s, int flags) { + return Base64.decode(s, flags); } public static String basic(String userInfo) { diff --git a/pyramid/src/main/java/com/undcover/freedom/pyramid/Spider.java b/pyramid/src/main/java/com/undcover/freedom/pyramid/Spider.java index f08c1cf92..4f305aaf4 100644 --- a/pyramid/src/main/java/com/undcover/freedom/pyramid/Spider.java +++ b/pyramid/src/main/java/com/undcover/freedom/pyramid/Spider.java @@ -2,24 +2,16 @@ package com.undcover.freedom.pyramid; import android.content.Context; -import androidx.collection.ArrayMap; - import com.chaquo.python.PyObject; import com.github.catvod.Proxy; -import com.github.catvod.net.OkHttp; -import com.github.catvod.utils.Json; -import com.google.common.net.HttpHeaders; +import com.github.catvod.utils.Util; import com.google.gson.Gson; -import com.google.gson.JsonObject; import java.io.ByteArrayInputStream; import java.util.HashMap; import java.util.List; import java.util.Map; -import fi.iki.elonen.NanoHTTPD; -import okhttp3.Headers; - public class Spider extends com.github.catvod.crawler.Spider { private final PyObject app; @@ -88,25 +80,26 @@ public class Spider extends com.github.catvod.crawler.Spider { } @Override - public Object[] proxyLocal(Map params) throws Exception { + public Object[] proxyLocal(Map params) { List list = app.callAttr("localProxy", obj, gson.toJson(params)).asList(); - JsonObject action = Json.parse(list.get(2).toString()).getAsJsonObject(); - Map headers = Json.toMap(action.get("header")); - String url = action.get("url").getAsString(); - String content = list.get(3).toString(); - String type = list.get(1).toString(); - int code = list.get(0).toInt(); - if (action.get("type").getAsString().equals("redirect")) { - NanoHTTPD.Response response = NanoHTTPD.newFixedLengthResponse(NanoHTTPD.Response.Status.lookup(code), NanoHTTPD.MIME_HTML, ""); - for (Map.Entry entry : headers.entrySet()) response.addHeader(entry.getKey(), entry.getValue()); - response.addHeader(HttpHeaders.LOCATION, url); - return new Object[]{response}; - } else if (action.get("type").getAsString().equals("stream")) { - ArrayMap param = Json.toArrayMap(action.get("param")); - return new Object[]{code, type, OkHttp.newCall(url, Headers.of(headers), param).execute().body().byteStream()}; + Map headers = list.size() > 3 ? list.get(3).asMap() : null; + boolean base64 = list.size() > 4 && list.get(4).toInt() == 1; + PyObject r2 = list.get(2); + Object[] result = new Object[4]; + result[0] = list.get(0).toInt(); + result[1] = list.get(1).toString(); + result[2] = r2 == null ? null : getStream(r2, base64); + result[3] = headers; + return result; + } + + private ByteArrayInputStream getStream(PyObject o, boolean base64) { + if (o.type().toString().contains("bytes")) { + return new ByteArrayInputStream(o.toJava(byte[].class)); } else { - if (content.isEmpty()) content = OkHttp.newCall(url, Headers.of(headers)).execute().body().string(); - return new Object[]{code, type, new ByteArrayInputStream(replaceProxy(content).getBytes())}; + String content = replaceProxy(o.toString()); + if (base64 && content.contains("base64,")) content = content.split("base64,")[1]; + return new ByteArrayInputStream(base64 ? Util.decode(content) : content.getBytes()); } } diff --git a/quickjs/src/main/java/com/fongmi/quickjs/bean/Info.java b/quickjs/src/main/java/com/fongmi/quickjs/bean/Info.java index 95d9fb4a0..74fd4da18 100644 --- a/quickjs/src/main/java/com/fongmi/quickjs/bean/Info.java +++ b/quickjs/src/main/java/com/fongmi/quickjs/bean/Info.java @@ -29,8 +29,9 @@ public class Info { pos = rules[0]; } try { - index = Integer.parseInt(pos.split("\\(")[1].split("\\)")[0]); + index = Integer.parseInt(pos.replace("eq(", "").replace(")", "")); } catch (Exception ignored) { + index = 0; } } diff --git a/quickjs/src/main/java/com/fongmi/quickjs/bean/Res.java b/quickjs/src/main/java/com/fongmi/quickjs/bean/Res.java index cec5aaf76..57d2f0406 100644 --- a/quickjs/src/main/java/com/fongmi/quickjs/bean/Res.java +++ b/quickjs/src/main/java/com/fongmi/quickjs/bean/Res.java @@ -1,9 +1,9 @@ package com.fongmi.quickjs.bean; import android.text.TextUtils; -import android.util.Base64; import com.github.catvod.utils.Json; +import com.github.catvod.utils.Util; import com.google.gson.Gson; import com.google.gson.JsonElement; import com.google.gson.annotations.SerializedName; @@ -57,7 +57,7 @@ public class Res { } public ByteArrayInputStream getStream() { - if (getBuffer() == 2) return new ByteArrayInputStream(Base64.decode(getContent(), Base64.DEFAULT)); + if (getBuffer() == 2) return new ByteArrayInputStream(Util.decode(getContent())); return new ByteArrayInputStream(getContent().getBytes()); } } diff --git a/quickjs/src/main/java/com/fongmi/quickjs/crawler/Spider.java b/quickjs/src/main/java/com/fongmi/quickjs/crawler/Spider.java index 0ea6fd31a..4a20fdcfc 100644 --- a/quickjs/src/main/java/com/fongmi/quickjs/crawler/Spider.java +++ b/quickjs/src/main/java/com/fongmi/quickjs/crawler/Spider.java @@ -13,6 +13,7 @@ import com.fongmi.quickjs.utils.JSUtil; import com.fongmi.quickjs.utils.Module; import com.github.catvod.utils.Asset; import com.github.catvod.utils.Json; +import com.github.catvod.utils.Util; import com.whl.quickjs.wrapper.JSArray; import com.whl.quickjs.wrapper.JSMethod; import com.whl.quickjs.wrapper.JSObject; @@ -228,10 +229,13 @@ public class Spider extends com.github.catvod.crawler.Spider { private Object[] proxy1(Map params) throws Exception { JSObject object = JSUtil.toObj(ctx, params); JSONArray array = new JSONArray(((JSArray) jsObject.getJSFunction("proxy").call(object)).stringify()); - Object[] result = new Object[3]; - result[0] = array.opt(0); - result[1] = array.opt(1); - result[2] = getStream(array.opt(2)); + Map headers = array.length() > 3 ? Json.toMap(array.optString(3)) : null; + boolean base64 = array.length() > 4 && array.optInt(4) == 1; + Object[] result = new Object[4]; + result[0] = array.optInt(0); + result[1] = array.optString(1); + result[2] = getStream(array.opt(2), base64); + result[3] = headers; return result; } @@ -249,15 +253,16 @@ public class Spider extends com.github.catvod.crawler.Spider { return result; } - private ByteArrayInputStream getStream(Object o) { + private ByteArrayInputStream getStream(Object o, boolean base64) { if (o instanceof JSONArray) { JSONArray a = (JSONArray) o; byte[] bytes = new byte[a.length()]; for (int i = 0; i < a.length(); i++) bytes[i] = (byte) a.optInt(i); return new ByteArrayInputStream(bytes); } else { - return new ByteArrayInputStream(o.toString().getBytes()); + String content = o.toString(); + if (base64 && content.contains("base64,")) content = content.split("base64,")[1]; + return new ByteArrayInputStream(base64 ? Util.decode(content) : content.getBytes()); } } } - diff --git a/quickjs/src/main/java/com/fongmi/quickjs/method/Global.java b/quickjs/src/main/java/com/fongmi/quickjs/method/Global.java index a7fc38879..b39d47f31 100644 --- a/quickjs/src/main/java/com/fongmi/quickjs/method/Global.java +++ b/quickjs/src/main/java/com/fongmi/quickjs/method/Global.java @@ -2,6 +2,7 @@ package com.fongmi.quickjs.method; import androidx.annotation.Keep; import androidx.annotation.NonNull; +import androidx.media3.common.util.UriUtil; import com.fongmi.quickjs.bean.Req; import com.fongmi.quickjs.utils.Connect; @@ -121,31 +122,31 @@ public class Global { @Keep @JSMethod public String pd(String html, String rule, String urlKey) { - return parser.pdfh(html, rule, urlKey); + return parser.parseDomForUrl(html, rule, urlKey); } @Keep @JSMethod public String pdfh(String html, String rule) { - return parser.pdfh(html, rule, ""); + return parser.parseDomForUrl(html, rule, ""); } @Keep @JSMethod public JSArray pdfa(String html, String rule) { - return JSUtil.toArray(ctx, parser.pdfa(html, rule)); + return JSUtil.toArray(ctx, parser.parseDomForArray(html, rule)); } @Keep @JSMethod public JSArray pdfl(String html, String rule, String texts, String urls, String urlKey) { - return JSUtil.toArray(ctx, parser.pdfl(html, rule, texts, urls, urlKey)); + return JSUtil.toArray(ctx, parser.parseDomForList(html, rule, texts, urls, urlKey)); } @Keep @JSMethod public String joinUrl(String parent, String child) { - return parser.joinUrl(parent, child); + return UriUtil.resolve(parent, child); } @Keep diff --git a/quickjs/src/main/java/com/fongmi/quickjs/utils/Connect.java b/quickjs/src/main/java/com/fongmi/quickjs/utils/Connect.java index d27972996..103d66a65 100644 --- a/quickjs/src/main/java/com/fongmi/quickjs/utils/Connect.java +++ b/quickjs/src/main/java/com/fongmi/quickjs/utils/Connect.java @@ -7,11 +7,10 @@ import com.github.catvod.utils.Util; import com.google.common.net.HttpHeaders; import com.whl.quickjs.wrapper.JSObject; import com.whl.quickjs.wrapper.QuickJSContext; -import java.security.SecureRandom; +import java.security.SecureRandom; import java.util.List; import java.util.Map; -import java.util.Random; import okhttp3.Call; import okhttp3.FormBody; diff --git a/quickjs/src/main/java/com/fongmi/quickjs/utils/Crypto.java b/quickjs/src/main/java/com/fongmi/quickjs/utils/Crypto.java index 28044e936..22d4b628b 100644 --- a/quickjs/src/main/java/com/fongmi/quickjs/utils/Crypto.java +++ b/quickjs/src/main/java/com/fongmi/quickjs/utils/Crypto.java @@ -2,6 +2,8 @@ package com.fongmi.quickjs.utils; import android.util.Base64; +import com.github.catvod.utils.Util; + import java.security.Key; import java.security.KeyFactory; import java.security.PublicKey; @@ -14,7 +16,6 @@ import java.util.Arrays; import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; -import com.github.catvod.utils.Util; public class Crypto { @@ -37,7 +38,7 @@ public class Crypto { SecretKeySpec keySpec = new SecretKeySpec(keyBuf, "AES"); if (iv == null) cipher.init(encrypt ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE, keySpec); else cipher.init(encrypt ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE, keySpec, new IvParameterSpec(ivBuf)); - byte[] inBuf = inBase64 ? Base64.decode(input.replaceAll("_", "/").replaceAll("-", "+"), Base64.DEFAULT) : input.getBytes("UTF-8"); + byte[] inBuf = inBase64 ? Base64.decode(input, Base64.DEFAULT | Base64.URL_SAFE) : input.getBytes("UTF-8"); return outBase64 ? Base64.encodeToString(cipher.doFinal(inBuf), Base64.NO_WRAP) : new String(cipher.doFinal(inBuf), "UTF-8"); } catch (Exception e) { e.printStackTrace(); @@ -50,7 +51,7 @@ public class Crypto { Key rsaKey = generateKey(pub, key); int len = getModulusLength(rsaKey); byte[] outBytes = new byte[0]; - byte[] inBytes = inBase64 ? Base64.decode(input.replaceAll("_", "/").replaceAll("-", "+"), Base64.DEFAULT) : input.getBytes("UTF-8"); + byte[] inBytes = inBase64 ? Base64.decode(input, Base64.DEFAULT | Base64.URL_SAFE) : input.getBytes("UTF-8"); Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); cipher.init(encrypt ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE, rsaKey); int blockLen = encrypt ? len / 8 - 11 : len / 8; diff --git a/quickjs/src/main/java/com/fongmi/quickjs/utils/Parser.java b/quickjs/src/main/java/com/fongmi/quickjs/utils/Parser.java index 8a216a1af..1aece436d 100644 --- a/quickjs/src/main/java/com/fongmi/quickjs/utils/Parser.java +++ b/quickjs/src/main/java/com/fongmi/quickjs/utils/Parser.java @@ -20,9 +20,9 @@ import java.util.regex.Pattern; public class Parser { - private final Pattern p1 = Pattern.compile("url\\((.*?)\\)", Pattern.MULTILINE | Pattern.DOTALL); - private final Pattern NO_ADD = Pattern.compile(":eq|:lt|:gt|:first|:last|^body$|^#"); - private final Pattern JOIN_URL = Pattern.compile("(url|src|href|-original|-src|-play|-url|style)$", Pattern.MULTILINE | Pattern.CASE_INSENSITIVE); + private final Pattern URL = Pattern.compile("url\\((.*?)\\)", Pattern.MULTILINE | Pattern.DOTALL); + private final Pattern NO_ADD = Pattern.compile(":eq|:lt|:gt|:first|:last|:not|:even|:odd|:has|:contains|:matches|:empty|^body$|^#"); + private final Pattern JOIN_URL = Pattern.compile("(url|src|href|-original|-src|-play|-url|style)$|^(data-|url-|src-)", Pattern.MULTILINE | Pattern.CASE_INSENSITIVE); private final Pattern SPEC_URL = Pattern.compile("^(ftp|magnet|thunder|ws):", Pattern.MULTILINE | Pattern.CASE_INSENSITIVE); private final Cache cache; @@ -47,7 +47,9 @@ public class Parser { private String parseHikerToJq(String parse, boolean first) { if (!parse.contains("&&")) { String[] split = parse.split(" "); - return (NO_ADD.matcher(split[split.length - 1]).find() || !first) ? parse : parse + ":eq(0)"; + Matcher m = NO_ADD.matcher(split[split.length - 1]); + if (!m.find() && first) parse = parse + ":eq(0)"; + return parse; } String[] parses = parse.split("&&"); List items = new ArrayList<>(); @@ -63,59 +65,7 @@ public class Parser { return TextUtils.join(" ", items); } - private Elements parseOneRule(Document doc, String parse, Elements elements) { - Info info = getParseInfo(parse); - if (parse.contains(":eq")) { - if (elements.isEmpty()) { - if (info.index < 0) { - Elements r = doc.select(info.rule); - elements = r.eq(r.size() + info.index); - } else { - elements = doc.select(info.rule).eq(info.index); - } - } else { - if (info.index < 0) { - Elements r = elements.select(info.rule); - elements = r.eq(r.size() + info.index); - } else { - elements = elements.select(info.rule).eq(info.index); - } - } - } else { - if (elements.isEmpty()) { - elements = doc.select(parse); - } else { - elements = elements.select(parse); - } - } - if (info.excludes != null && !elements.isEmpty()) { - elements = elements.clone(); - for (String exclude : info.excludes) { - elements.select(exclude).remove(); - } - } - return elements; - } - - public String joinUrl(String parent, String child) { - return UriUtil.resolve(parent, child); - } - - public List pdfa(String html, String rule) { - Document doc = cache.getPdfa(html); - rule = parseHikerToJq(rule, false); - String[] parses = rule.split(" "); - Elements elements = new Elements(); - for (String parse : parses) { - elements = parseOneRule(doc, parse, elements); - if (elements.isEmpty()) return Collections.emptyList(); - } - List items = new ArrayList<>(); - for (Element element : elements) items.add(element.outerHtml()); - return items; - } - - public String pdfh(String html, String rule, String addUrl) { + public String parseDomForUrl(String html, String rule, String addUrl) { Document doc = cache.getPdfh(html); if ("body&&Text".equals(rule) || "Text".equals(rule)) { return doc.text(); @@ -143,23 +93,69 @@ public class Parser { } else if ("Html".equals(option)) { return elements.html(); } else { - String result = elements.attr(option); - if (option.toLowerCase().contains("style") && result.contains("url(")) { - Matcher matcher = p1.matcher(result); - if (matcher.find()) result = matcher.group(1); - if (result != null) result = result.replaceAll("^['|\"](.*)['|\"]$", "$1"); - } - if (!TextUtils.isEmpty(result) && !TextUtils.isEmpty(addUrl)) { - if (JOIN_URL.matcher(option).find() && !SPEC_URL.matcher(result).find()) { - if (result.contains("http")) result = result.substring(result.indexOf("http")); - else result = joinUrl(addUrl, result); + String result = ""; + for (String s : option.split("[||]")) { + result = elements.attr(s); + if (s.toLowerCase().contains("style") && result.contains("url(")) { + Matcher m = URL.matcher(result); + if (m.find()) result = m.group(1); + result = result.replaceAll("^['|\"](.*)['|\"]$", "$1"); + } + if (!result.isEmpty() && !addUrl.isEmpty()) { + if (JOIN_URL.matcher(s).find() && !SPEC_URL.matcher(result).find()) { + if (result.contains("http")) { + result = result.substring(result.indexOf("http")); + } else { + result = UriUtil.resolve(addUrl, result); + } + } + } + if (!result.isEmpty()) { + return result; } } return result; } } - public List pdfl(String html, String rule, String texts, String urls, String urlKey) { + public List parseDomForArray(String html, String rule) { + Document doc = cache.getPdfa(html); + rule = parseHikerToJq(rule, false); + String[] parses = rule.split(" "); + Elements elements = new Elements(); + for (String parse : parses) { + elements = parseOneRule(doc, parse, elements); + if (elements.isEmpty()) return new ArrayList<>(); + } + List items = new ArrayList<>(); + for (Element element : elements) items.add(element.outerHtml()); + return items; + } + + private Elements parseOneRule(Document doc, String parse, Elements elements) { + Info info = getParseInfo(parse); + if (elements.isEmpty()) { + elements = doc.select(info.rule); + } else { + elements = elements.select(info.rule); + } + if (parse.contains(":eq")) { + if (info.index < 0) { + elements = elements.eq(elements.size() + info.index); + } else { + elements = elements.eq(info.index); + } + } + if (info.excludes != null && !elements.isEmpty()) { + elements = elements.clone(); + for (int i = 0; i < info.excludes.size(); i++) { + elements.select(info.excludes.get(i)).remove(); + } + } + return elements; + } + + public List parseDomForList(String html, String rule, String texts, String urls, String urlKey) { String[] parses = parseHikerToJq(rule, false).split(" "); Elements elements = new Elements(); for (String parse : parses) { @@ -169,7 +165,7 @@ public class Parser { List items = new ArrayList<>(); for (Element element : elements) { html = element.outerHtml(); - items.add(pdfh(html, texts, "").trim() + '$' + pdfh(html, urls, urlKey)); + items.add(parseDomForUrl(html, texts, "").trim() + '$' + parseDomForUrl(html, urls, urlKey)); } return items; }