You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
212 lines
7.7 KiB
212 lines
7.7 KiB
package com.github.catvod.crawler;
|
|
|
|
import android.content.Context;
|
|
|
|
import com.github.tvbox.osc.base.App;
|
|
import com.github.tvbox.osc.util.MD5;
|
|
import com.github.tvbox.osc.util.js.SpiderJS;
|
|
import com.lzy.okgo.OkGo;
|
|
|
|
import org.json.JSONObject;
|
|
|
|
import java.io.File;
|
|
import java.io.FileOutputStream;
|
|
import java.io.InputStream;
|
|
import java.io.OutputStream;
|
|
import java.lang.reflect.Method;
|
|
import java.util.HashMap;
|
|
import java.util.LinkedHashMap;
|
|
import java.util.Map;
|
|
import java.util.concurrent.ConcurrentHashMap;
|
|
|
|
import dalvik.system.DexClassLoader;
|
|
import okhttp3.Response;
|
|
|
|
public class JarLoader {
|
|
private ConcurrentHashMap<String, DexClassLoader> classLoaders = new ConcurrentHashMap<>();
|
|
private ConcurrentHashMap<String, Method> proxyMethods = new ConcurrentHashMap<>();
|
|
private ConcurrentHashMap<String, Spider> spiders = new ConcurrentHashMap<>();
|
|
private volatile String recentJarKey = "";
|
|
|
|
/**
|
|
* 不要在主线程调用我
|
|
*
|
|
* @param cache
|
|
*/
|
|
public boolean load(String cache) {
|
|
spiders.clear();
|
|
recentJarKey = "main";
|
|
proxyMethods.clear();
|
|
classLoaders.clear();
|
|
return loadClassLoader(cache, "main");
|
|
}
|
|
|
|
private boolean loadClassLoader(String jar, String key) {
|
|
boolean success = false;
|
|
try {
|
|
File cacheDir = new File(App.getInstance().getCacheDir().getAbsolutePath() + "/catvod_csp");
|
|
if (!cacheDir.exists())
|
|
cacheDir.mkdirs();
|
|
DexClassLoader classLoader = new DexClassLoader(jar, cacheDir.getAbsolutePath(), null, App.getInstance().getClassLoader());
|
|
// make force wait here, some device async dex load
|
|
int count = 0;
|
|
do {
|
|
try {
|
|
Class classInit = classLoader.loadClass("com.github.catvod.spider.Init");
|
|
if (classInit != null) {
|
|
Method method = classInit.getMethod("init", Context.class);
|
|
method.invoke(null, App.getInstance());
|
|
System.out.println("自定义爬虫代码加载成功!");
|
|
success = true;
|
|
try {
|
|
Class proxy = classLoader.loadClass("com.github.catvod.spider.Proxy");
|
|
Method mth = proxy.getMethod("proxy", Map.class);
|
|
proxyMethods.put(key, mth);
|
|
} catch (Throwable th) {
|
|
|
|
}
|
|
break;
|
|
}
|
|
Thread.sleep(200);
|
|
} catch (Throwable th) {
|
|
th.printStackTrace();
|
|
}
|
|
count++;
|
|
} while (count < 5);
|
|
|
|
if (success) {
|
|
classLoaders.put(key, classLoader);
|
|
}
|
|
} catch (Throwable th) {
|
|
th.printStackTrace();
|
|
}
|
|
return success;
|
|
}
|
|
|
|
private DexClassLoader loadJarInternal(String jar, String md5, String key) {
|
|
if (classLoaders.contains(key))
|
|
return classLoaders.get(key);
|
|
File cache = new File(App.getInstance().getFilesDir().getAbsolutePath() + "/" + key + ".jar");
|
|
if (!md5.isEmpty()) {
|
|
if (cache.exists() && MD5.getFileMd5(cache).equalsIgnoreCase(md5)) {
|
|
loadClassLoader(cache.getAbsolutePath(), key);
|
|
return classLoaders.get(key);
|
|
}
|
|
}
|
|
try {
|
|
Response response = OkGo.<File>get(jar).execute();
|
|
InputStream is = response.body().byteStream();
|
|
OutputStream os = new FileOutputStream(cache);
|
|
try {
|
|
byte[] buffer = new byte[2048];
|
|
int length;
|
|
while ((length = is.read(buffer)) > 0) {
|
|
os.write(buffer, 0, length);
|
|
}
|
|
} finally {
|
|
try {
|
|
is.close();
|
|
os.close();
|
|
} catch (Exception e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
loadClassLoader(cache.getAbsolutePath(), key);
|
|
return classLoaders.get(key);
|
|
} catch (Throwable e) {
|
|
e.printStackTrace();
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public Spider getSpider(String key, String cls, String ext, String jar) {
|
|
if (cls.toLowerCase().endsWith(".js") || cls.toLowerCase().contains(".js?")) {
|
|
if (spiders.containsKey(key))
|
|
return spiders.get(key);
|
|
try {
|
|
SpiderJS sp = new SpiderJS(key, cls, ext);
|
|
sp.init(App.getInstance(), ext);
|
|
spiders.put(key, sp);
|
|
return sp;
|
|
} catch (Throwable th) {
|
|
th.printStackTrace();
|
|
}
|
|
return null;
|
|
}
|
|
String clsKey = cls.replace("csp_", "");
|
|
String jarUrl = "";
|
|
String jarMd5 = "";
|
|
String jarKey = "";
|
|
if (jar.isEmpty()) {
|
|
jarKey = "main";
|
|
} else {
|
|
String[] urls = jar.split(";md5;");
|
|
jarUrl = urls[0];
|
|
jarKey = MD5.string2MD5(jarUrl);
|
|
jarMd5 = urls.length > 1 ? urls[1].trim() : "";
|
|
}
|
|
recentJarKey = jarKey;
|
|
if (spiders.containsKey(key))
|
|
return spiders.get(key);
|
|
DexClassLoader classLoader = null;
|
|
if (jarKey.equals("main"))
|
|
classLoader = classLoaders.get("main");
|
|
else {
|
|
classLoader = loadJarInternal(jarUrl, jarMd5, jarKey);
|
|
}
|
|
if (classLoader == null)
|
|
return new SpiderNull();
|
|
try {
|
|
Spider sp = (Spider) classLoader.loadClass("com.github.catvod.spider." + clsKey).newInstance();
|
|
sp.init(App.getInstance(), ext);
|
|
if (!jar.isEmpty()) {
|
|
sp.homeContent(false); // 增加此行 应该可以解决部分写的有问题源的历史记录问题 但会增加这个源的首次加载时间 不需要可以已删掉
|
|
}
|
|
spiders.put(key, sp);
|
|
return sp;
|
|
} catch (Throwable th) {
|
|
th.printStackTrace();
|
|
}
|
|
return new SpiderNull();
|
|
}
|
|
|
|
public JSONObject jsonExt(String key, LinkedHashMap<String, String> jxs, String url) {
|
|
try {
|
|
DexClassLoader classLoader = classLoaders.get("main");
|
|
String clsKey = "Json" + key;
|
|
String hotClass = "com.github.catvod.parser." + clsKey;
|
|
Class jsonParserCls = classLoader.loadClass(hotClass);
|
|
Method mth = jsonParserCls.getMethod("parse", LinkedHashMap.class, String.class);
|
|
return (JSONObject) mth.invoke(null, jxs, url);
|
|
} catch (Throwable th) {
|
|
th.printStackTrace();
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public JSONObject jsonExtMix(String flag, String key, String name, LinkedHashMap<String, HashMap<String, String>> jxs, String url) {
|
|
try {
|
|
DexClassLoader classLoader = classLoaders.get("main");
|
|
String clsKey = "Mix" + key;
|
|
String hotClass = "com.github.catvod.parser." + clsKey;
|
|
Class jsonParserCls = classLoader.loadClass(hotClass);
|
|
Method mth = jsonParserCls.getMethod("parse", LinkedHashMap.class, String.class, String.class, String.class);
|
|
return (JSONObject) mth.invoke(null, jxs, name, flag, url);
|
|
} catch (Throwable th) {
|
|
th.printStackTrace();
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public Object[] proxyInvoke(Map params) {
|
|
try {
|
|
Method proxyFun = proxyMethods.get(recentJarKey);
|
|
if (proxyFun != null) {
|
|
return (Object[]) proxyFun.invoke(null, params);
|
|
}
|
|
} catch (Throwable th) {
|
|
|
|
}
|
|
return null;
|
|
}
|
|
}
|
|
|