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 classLoaders = new ConcurrentHashMap<>(); private ConcurrentHashMap proxyMethods = new ConcurrentHashMap<>(); private ConcurrentHashMap 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.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 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> 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; } }