From 611bf5dbc83fa1cb5be1dba979a86ab110f7514a Mon Sep 17 00:00:00 2001 From: jun <215613905@qq.com> Date: Wed, 26 Mar 2025 00:25:58 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B0=9D=E8=AF=95=E5=85=BC=E5=AE=B9py=E7=9B=B4?= =?UTF-8?q?=E6=92=AD(=E5=88=9D=E7=89=88)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/github/catvod/crawler/PyLoader.java | 72 +++++++ .../com/github/tvbox/osc/api/ApiConfig.java | 41 +++- .../osc/ui/activity/LivePlayActivity.java | 183 +++++++++++++----- gradle.properties | 2 +- 4 files changed, 246 insertions(+), 52 deletions(-) diff --git a/app/src/main/java/com/github/catvod/crawler/PyLoader.java b/app/src/main/java/com/github/catvod/crawler/PyLoader.java index 137d9444..0028c674 100644 --- a/app/src/main/java/com/github/catvod/crawler/PyLoader.java +++ b/app/src/main/java/com/github/catvod/crawler/PyLoader.java @@ -2,8 +2,17 @@ package com.github.catvod.crawler; import android.util.Log; +import com.chaquo.python.PyObject; import com.github.tvbox.osc.base.App; +import com.github.tvbox.osc.util.LOG; +import com.github.tvbox.osc.util.MD5; import com.undcover.freedom.pyramid.PythonLoader; +import com.undcover.freedom.pyramid.PythonSpider; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.lang.reflect.Field; +import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public class PyLoader { @@ -21,6 +30,11 @@ public class PyLoader { lastConfig = jsonStr; } } + + private String recentPyApi; + public void setRecentPyKey(String pyApi) { + recentPyApi=pyApi; + } public Spider getSpider(String key, String cls, String ext) { if (spiders.containsKey(key)){ Log.i("PyLoader","echo-getSpider spider缓存: " + key); @@ -49,6 +63,64 @@ public class PyLoader { return null; } + public Object[] proxyInvoke(Map params) { + try { + LOG.i("echo-recentPyApi"+recentPyApi); +// return (Object[])pythonLoader.proxyLocal(MD5.string2MD5(recentPyApi), recentPyApi, params); + PythonSpider originalSpider = (PythonSpider) pythonLoader.getSpider(MD5.string2MD5(recentPyApi), recentPyApi); + PythonSpiderWrapper wrapper = new PythonSpiderWrapper(originalSpider); + // LOG.i("echo-list:---"+wrapper.liveContent(recentPyApi)); + return wrapper.proxyLocal(params); + } catch (Throwable th) { + LOG.i("echo-Throwable:---"+th.getMessage()); + th.printStackTrace(); + } + return null; + } + + public static class PythonSpiderWrapper { + private final PythonSpider spider; + + public PythonSpiderWrapper(PythonSpider spider) { + this.spider = spider; + } + + public Object[] proxyLocal(Map param) { + try { + // 使用反射获取私有字段 app + Field appField = PythonSpider.class.getDeclaredField("app"); + appField.setAccessible(true); + PyObject app = (PyObject) appField.get(spider); + + // 使用反射获取私有字段 pySpider + Field pySpiderField = PythonSpider.class.getDeclaredField("pySpider"); + pySpiderField.setAccessible(true); + PyObject pySpider = (PyObject) pySpiderField.get(spider); + + // 调用 Python 接口获取原始结果 + assert app != null; + List poList = app.callAttr("localProxy", + new Object[]{pySpider, spider.map2json(param).toString()}).asList(); + // 提取前三个元素 + int code = poList.get(0).toInt(); + String type = poList.get(1).toString(); + String action = poList.get(2).toString(); +// LOG.i("echo-action:---"+action); + InputStream stream = new ByteArrayInputStream(action.getBytes("utf8")); + // 如果存在第四个元素,则将其转换为 Map,否则设为 null + Object extra = null; + if (poList.size() > 3) { + extra = poList.get(3).toJava(Map.class); + } + + return new Object[]{code, type, stream, extra}; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + } + private String getPyUrl(String api,String ext) { StringBuilder urlBuilder = new StringBuilder(api); diff --git a/app/src/main/java/com/github/tvbox/osc/api/ApiConfig.java b/app/src/main/java/com/github/tvbox/osc/api/ApiConfig.java index 2f370f17..0fff032f 100644 --- a/app/src/main/java/com/github/tvbox/osc/api/ApiConfig.java +++ b/app/src/main/java/com/github/tvbox/osc/api/ApiConfig.java @@ -816,7 +816,9 @@ public class ApiConfig { } else { String type= livesOBJ.get("type").getAsString(); if(type.equals("0") || type.equals("3")){ - url = livesOBJ.get("url").getAsString(); + url = livesOBJ.has("url")?livesOBJ.get("url").getAsString():""; + if(url.isEmpty())url=livesOBJ.has("api")?livesOBJ.get("api").getAsString():""; + LOG.i("echo-liveurl"+url); if(!url.startsWith("http://127.0.0.1")){ if(url.startsWith("http")){ url = Base64.encodeToString(url.getBytes("UTF-8"), Base64.DEFAULT | Base64.URL_SAFE | Base64.NO_WRAP); @@ -824,7 +826,13 @@ public class ApiConfig { url ="http://127.0.0.1:9978/proxy?do=live&type=txt&ext="+url; } if(type.equals("3")){ - String jarUrl = livesOBJ.get("jar").getAsString().trim(); + String jarUrl = livesOBJ.has("jar")?livesOBJ.get("jar").getAsString().trim():""; + String pyApi = livesOBJ.has("api")?livesOBJ.get("api").getAsString().trim():""; + LOG.i("echo-pyApi1"+pyApi); + if(pyApi.contains(".py")){ + String ext=livesOBJ.has("ext")?livesOBJ.get("ext").getAsJsonObject().toString().trim():""; + pyLoader.getSpider(MD5.string2MD5(pyApi),pyApi,ext); + } if(!jarUrl.isEmpty()){ jarLoader.loadLiveJar(jarUrl); }else if(!liveSpider.isEmpty()){ @@ -864,10 +872,16 @@ public class ApiConfig { } } + private String currentLiveSpider; public void setLiveJar(String liveJar) { - String jarUrl=!liveJar.isEmpty()?liveJar:liveSpider; - jarLoader.setRecentJarKey(MD5.string2MD5(jarUrl)); + if(liveJar.contains(".py")){ + pyLoader.setRecentPyKey(liveJar); + }else { + String jarUrl=!liveJar.isEmpty()?liveJar:liveSpider; + jarLoader.setRecentJarKey(MD5.string2MD5(jarUrl)); + } + currentLiveSpider=liveJar; } public String getSpider() { @@ -884,12 +898,25 @@ public class ApiConfig { else return jarLoader.getSpider(sourceBean.getKey(), sourceBean.getApi(), sourceBean.getExt(), sourceBean.getJar()); } + public Spider getPyCSP(String url) { + return pyLoader.getSpider(MD5.string2MD5(url), url, ""); + } + public Object[] proxyLocal(Map param) { SourceBean sourceBean = ApiConfig.get().getHomeSourceBean(); - if (sourceBean.getKey().startsWith("py_")) { - return pyLoader.proxyInvoke(param,sourceBean.getKey(),sourceBean.getApi(),sourceBean.getExt()); + + if(Hawk.get(HawkConfig.PLAYER_IS_LIVE,false)){ + if(currentLiveSpider.contains(".py")){ + return pyLoader.proxyInvoke(param); + }else { + return jarLoader.proxyInvoke(param); + } }else { - return jarLoader.proxyInvoke(param); + if (sourceBean.getKey().startsWith("py_")) { + return pyLoader.proxyInvoke(param); + }else { + return jarLoader.proxyInvoke(param); + } } } 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 6deb7fd8..58a3f5f2 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 @@ -27,6 +27,7 @@ import androidx.core.content.ContextCompat; import androidx.recyclerview.widget.RecyclerView; import com.chad.library.adapter.base.BaseQuickAdapter; +import com.github.catvod.crawler.Spider; import com.github.tvbox.osc.R; import com.github.tvbox.osc.api.ApiConfig; import com.github.tvbox.osc.base.App; @@ -87,6 +88,13 @@ import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.TimeZone; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -932,8 +940,17 @@ public class LivePlayActivity extends BaseActivity { logoUrl = livesOBJ.get("logo").getAsString(); } if(type.equals("3")){ - String jarUrl=livesOBJ.has("jar")?livesOBJ.get("jar").getAsString():""; - ApiConfig.get().setLiveJar(jarUrl); + String py_jar=""; + if(livesOBJ.has("jar")){ + py_jar=livesOBJ.has("jar")?livesOBJ.get("jar").getAsString():""; + + }else if(livesOBJ.has("api")){ + py_jar=livesOBJ.has("api")?livesOBJ.get("api").getAsString():""; +// String ext = livesOBJ.has("ext")?livesOBJ.get("ext").getAsJsonObject().toString():"{}"; +// LOG.i("echo-ext:"+ext); + py_jar=py_jar+"?extend="+(livesOBJ.has("ext")?livesOBJ.get("ext").getAsJsonObject().toString():"{}"); + } + ApiConfig.get().setLiveJar(py_jar); } } @@ -1849,55 +1866,133 @@ public class LivePlayActivity extends BaseActivity { showLoading(); LOG.i("echo-live-url:"+url); - OkGo.get(url).execute(new AbsCallback() { - @Override - public String convertResponse(okhttp3.Response response) throws Throwable { - assert response.body() != null; - return response.body().string(); - } + if(url.contains(".py")){ + String finalUrl = url; + Runnable waitResponse = new Runnable() { + @Override + public void run() { + ExecutorService executor = Executors.newSingleThreadExecutor(); + Future future = executor.submit(new Callable() { + @Override + public String call() throws Exception { + Spider sp = ApiConfig.get().getPyCSP(finalUrl); + String json=sp.homeContent(true); + LOG.i("echo--loadProxyLives-json--"+json); + return json; + } + }); + String sortJson = null; + try { + sortJson = future.get(10, TimeUnit.SECONDS); + } catch (TimeoutException e) { + e.printStackTrace(); + future.cancel(true); + } catch (InterruptedException | ExecutionException e) { + e.printStackTrace(); + } finally { + // 将字符串转换为 JSONObject + try { + JSONObject jsonObject = new JSONObject(sortJson); + sortJson = jsonObject.getString("liveList"); + } catch (JSONException e) { + Toast.makeText(App.getInstance(), "加载错误,请重试", Toast.LENGTH_SHORT).show(); + JsonArray live_groups=Hawk.get(HawkConfig.LIVE_GROUP_LIST,new JsonArray()); + Hawk.put(HawkConfig.LIVE_GROUP_INDEX,Hawk.get(HawkConfig.LIVE_GROUP_INDEX,0)+1); + if(Hawk.get(HawkConfig.LIVE_GROUP_INDEX,0)>live_groups.size()-1){ + Hawk.put(HawkConfig.LIVE_GROUP_INDEX,0); + } + mHandler.post(new Runnable() { + @Override + public void run() { + jumpActivity(HomeActivity.class); + } + }); + return; + } + JsonArray livesArray; + LinkedHashMap>> linkedHashMap = new LinkedHashMap<>(); + TxtSubscribe.parse(linkedHashMap, sortJson); + livesArray = TxtSubscribe.live2JsonArray(linkedHashMap); + + ApiConfig.get().loadLives(livesArray); + List list = ApiConfig.get().getChannelGroupList(); + if (list.isEmpty()) { + Toast.makeText(App.getInstance(), "频道列表为空", Toast.LENGTH_SHORT).show(); + finish(); + return; + } + liveChannelGroupList.clear(); + liveChannelGroupList.addAll(list); + + mHandler.post(new Runnable() { + @Override + public void run() { + LivePlayActivity.this.showSuccess(); + initLiveState(); + } + }); + try { + executor.shutdown(); + } catch (Throwable th) { + th.printStackTrace(); + } + } + } + }; + Executors.newSingleThreadExecutor().execute(waitResponse); + }else { + OkGo.get(url).execute(new AbsCallback() { - @Override - public void onSuccess(Response response) { - JsonArray livesArray; - LinkedHashMap>> linkedHashMap = new LinkedHashMap<>(); - TxtSubscribe.parse(linkedHashMap, response.body()); - livesArray = TxtSubscribe.live2JsonArray(linkedHashMap); - - ApiConfig.get().loadLives(livesArray); - List list = ApiConfig.get().getChannelGroupList(); - if (list.isEmpty()) { - Toast.makeText(App.getInstance(), "频道列表为空", Toast.LENGTH_SHORT).show(); - finish(); - return; + @Override + public String convertResponse(okhttp3.Response response) throws Throwable { + assert response.body() != null; + return response.body().string(); } - liveChannelGroupList.clear(); - liveChannelGroupList.addAll(list); - mHandler.post(new Runnable() { - @Override - public void run() { - LivePlayActivity.this.showSuccess(); - initLiveState(); + @Override + public void onSuccess(Response response) { + JsonArray livesArray; + LinkedHashMap>> linkedHashMap = new LinkedHashMap<>(); + TxtSubscribe.parse(linkedHashMap, response.body()); + livesArray = TxtSubscribe.live2JsonArray(linkedHashMap); + + ApiConfig.get().loadLives(livesArray); + List list = ApiConfig.get().getChannelGroupList(); + if (list.isEmpty()) { + Toast.makeText(App.getInstance(), "频道列表为空", Toast.LENGTH_SHORT).show(); + finish(); + return; } - }); - } - @Override - public void onError(Response response) { - Toast.makeText(App.getInstance(), "加载错误,请重试", Toast.LENGTH_SHORT).show(); - JsonArray live_groups=Hawk.get(HawkConfig.LIVE_GROUP_LIST,new JsonArray()); - Hawk.put(HawkConfig.LIVE_GROUP_INDEX,Hawk.get(HawkConfig.LIVE_GROUP_INDEX,0)+1); - if(Hawk.get(HawkConfig.LIVE_GROUP_INDEX,0)>live_groups.size()-1){ - Hawk.put(HawkConfig.LIVE_GROUP_INDEX,0); + liveChannelGroupList.clear(); + liveChannelGroupList.addAll(list); + + mHandler.post(new Runnable() { + @Override + public void run() { + LivePlayActivity.this.showSuccess(); + initLiveState(); + } + }); } - mHandler.post(new Runnable() { - @Override - public void run() { - jumpActivity(HomeActivity.class); + @Override + public void onError(Response response) { + Toast.makeText(App.getInstance(), "加载错误,请重试", Toast.LENGTH_SHORT).show(); + JsonArray live_groups=Hawk.get(HawkConfig.LIVE_GROUP_LIST,new JsonArray()); + Hawk.put(HawkConfig.LIVE_GROUP_INDEX,Hawk.get(HawkConfig.LIVE_GROUP_INDEX,0)+1); + if(Hawk.get(HawkConfig.LIVE_GROUP_INDEX,0)>live_groups.size()-1){ + Hawk.put(HawkConfig.LIVE_GROUP_INDEX,0); } - }); - } - }); + mHandler.post(new Runnable() { + @Override + public void run() { + jumpActivity(HomeActivity.class); + } + }); + } + }); + + } } private void initLiveState() { diff --git a/gradle.properties b/gradle.properties index 8b1a2183..e86424f0 100644 --- a/gradle.properties +++ b/gradle.properties @@ -17,4 +17,4 @@ android.useAndroidX=true # Automatically convert third-party libraries to use AndroidX android.enableJetifier=true IsDebug=true -#org.gradle.jvmargs=-Xmx2048m --add-opens java.base/java.io=ALL-UNNAMED +org.gradle.jvmargs=-Xmx2048m --add-opens java.base/java.io=ALL-UNNAMED