尝试兼容py直播(初版)

pull/144/head
jun 1 year ago
parent b033ec4539
commit 611bf5dbc8
  1. 72
      app/src/main/java/com/github/catvod/crawler/PyLoader.java
  2. 41
      app/src/main/java/com/github/tvbox/osc/api/ApiConfig.java
  3. 183
      app/src/main/java/com/github/tvbox/osc/ui/activity/LivePlayActivity.java
  4. 2
      gradle.properties

@ -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<String,String> 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<String,String> 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<PyObject> 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);

@ -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<String,String> 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);
}
}
}

@ -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.<String>get(url).execute(new AbsCallback<String>() {
@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<String> future = executor.submit(new Callable<String>() {
@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<String, LinkedHashMap<String, ArrayList<String>>> linkedHashMap = new LinkedHashMap<>();
TxtSubscribe.parse(linkedHashMap, sortJson);
livesArray = TxtSubscribe.live2JsonArray(linkedHashMap);
ApiConfig.get().loadLives(livesArray);
List<LiveChannelGroup> 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.<String>get(url).execute(new AbsCallback<String>() {
@Override
public void onSuccess(Response<String> response) {
JsonArray livesArray;
LinkedHashMap<String, LinkedHashMap<String, ArrayList<String>>> linkedHashMap = new LinkedHashMap<>();
TxtSubscribe.parse(linkedHashMap, response.body());
livesArray = TxtSubscribe.live2JsonArray(linkedHashMap);
ApiConfig.get().loadLives(livesArray);
List<LiveChannelGroup> 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<String> response) {
JsonArray livesArray;
LinkedHashMap<String, LinkedHashMap<String, ArrayList<String>>> linkedHashMap = new LinkedHashMap<>();
TxtSubscribe.parse(linkedHashMap, response.body());
livesArray = TxtSubscribe.live2JsonArray(linkedHashMap);
ApiConfig.get().loadLives(livesArray);
List<LiveChannelGroup> list = ApiConfig.get().getChannelGroupList();
if (list.isEmpty()) {
Toast.makeText(App.getInstance(), "频道列表为空", Toast.LENGTH_SHORT).show();
finish();
return;
}
});
}
@Override
public void onError(Response<String> 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<String> 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() {

@ -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

Loading…
Cancel
Save