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.
 
 
 
 
 
FONGMITV/quickjs/src/main/java/com/fongmi/quickjs/crawler/Spider.java

228 lines
7.9 KiB

package com.fongmi.quickjs.crawler;
import android.content.Context;
import com.fongmi.quickjs.bean.Res;
import com.fongmi.quickjs.method.Async;
import com.fongmi.quickjs.method.Console;
import com.fongmi.quickjs.method.Global;
import com.fongmi.quickjs.method.Local;
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.UriUtil;
import com.github.catvod.utils.Util;
import com.whl.quickjs.wrapper.JSArray;
import com.whl.quickjs.wrapper.JSObject;
import com.whl.quickjs.wrapper.QuickJSContext;
import org.json.JSONArray;
import java.io.ByteArrayInputStream;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java9.util.concurrent.CompletableFuture;
public class Spider extends com.github.catvod.crawler.Spider {
private final ExecutorService executor;
private QuickJSContext ctx;
private JSObject jsObject;
private final String key;
private final String api;
private boolean cat;
public Spider(String key, String api) throws Exception {
this.executor = Executors.newSingleThreadExecutor();
this.key = key;
this.api = api;
initializeJS();
}
private void submit(Runnable runnable) {
executor.submit(runnable);
}
private <T> Future<T> submit(Callable<T> callable) {
return executor.submit(callable);
}
private Object call(String func, Object... args) throws Exception {
//return executor.submit((Function.call(jsObject, func, args))).get();
return CompletableFuture.supplyAsync(() -> Async.run(jsObject, func, args), executor).join().get();
}
@Override
public void init(Context context, String extend) throws Exception {
if (cat) call("init", submit(() -> cfg(extend)).get());
else call("init", Json.valid(extend) ? ctx.parse(extend) : extend);
}
@Override
public String homeContent(boolean filter) throws Exception {
return (String) call("home", filter);
}
@Override
public String homeVideoContent() throws Exception {
return (String) call("homeVod");
}
@Override
public String categoryContent(String tid, String pg, boolean filter, HashMap<String, String> extend) throws Exception {
JSObject obj = submit(() -> JSUtil.toObj(ctx, extend)).get();
return (String) call("category", tid, pg, filter, obj);
}
@Override
public String detailContent(List<String> ids) throws Exception {
return (String) call("detail", ids.get(0));
}
@Override
public String searchContent(String key, boolean quick) throws Exception {
return (String) call("search", key, quick);
}
@Override
public String searchContent(String key, boolean quick, String pg) throws Exception {
return (String) call("search", key, quick, pg);
}
@Override
public String playerContent(String flag, String id, List<String> vipFlags) throws Exception {
JSArray array = submit(() -> JSUtil.toArray(ctx, vipFlags)).get();
return (String) call("play", flag, id, array);
}
@Override
public String liveContent() throws Exception {
return (String) call("live");
}
@Override
public boolean manualVideoCheck() throws Exception {
return (Boolean) call("sniffer");
}
@Override
public boolean isVideoFormat(String url) throws Exception {
return (Boolean) call("isVideo", url);
}
@Override
public Object[] proxyLocal(Map<String, String> params) throws Exception {
if ("catvod".equals(params.get("from"))) return proxy2(params);
else return submit(() -> proxy1(params)).get();
}
@Override
public void destroy() {
try {
call("destroy");
} catch (Throwable e) {
e.printStackTrace();
}
submit(() -> {
executor.shutdownNow();
ctx.destroy();
});
}
private void initializeJS() throws Exception {
submit(() -> {
if (ctx == null) createCtx();
createObj();
return null;
}).get();
}
private void createCtx() {
ctx = QuickJSContext.create();
ctx.setConsole(new Console());
ctx.evaluate(Asset.read("js/lib/http.js"));
Global.create(ctx, executor).setProperty();
ctx.getGlobalObject().setProperty("local", Local.class);
ctx.setModuleLoader(new QuickJSContext.BytecodeModuleLoader() {
@Override
public String moduleNormalizeName(String baseModuleName, String moduleName) {
return UriUtil.resolve(baseModuleName, moduleName);
}
@Override
public byte[] getModuleBytecode(String moduleName) {
String content = Module.get().fetch(moduleName);
return content.startsWith("//bb") ? Module.get().bb(content) : ctx.compileModule(content, moduleName);
}
});
}
private void createObj() {
String jsEval = "__jsEvalReturn";
String spider = "__JS_SPIDER__";
String global = "globalThis." + spider;
String content = Module.get().fetch(api);
if (content.startsWith("//bb")) ctx.execute(Module.get().bb(content));
else ctx.evaluateModule(content.replace(spider, global), api);
ctx.evaluateModule(String.format(Asset.read("js/lib/spider.js"), api));
if (content.startsWith("//bb") || content.contains(jsEval)) cat = true;
jsObject = (JSObject) ctx.getProperty(ctx.getGlobalObject(), spider);
}
private JSObject cfg(String ext) {
JSObject cfg = ctx.createNewJSObject();
cfg.setProperty("stype", 3);
cfg.setProperty("skey", key);
if (Json.invalid(ext)) cfg.setProperty("ext", ext);
else cfg.setProperty("ext", (JSObject) ctx.parse(ext));
return cfg;
}
private Object[] proxy1(Map<String, String> params) throws Exception {
JSObject object = JSUtil.toObj(ctx, params);
JSONArray array = new JSONArray(((JSArray) jsObject.getJSFunction("proxy").call(object)).stringify());
Map<String, String> 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;
}
private Object[] proxy2(Map<String, String> params) throws Exception {
String url = params.get("url");
String header = params.get("header");
JSArray array = submit(() -> JSUtil.toArray(ctx, Arrays.asList(url.split("/")))).get();
Object object = submit(() -> ctx.parse(header)).get();
String json = (String) call("proxy", array, object);
Res res = Res.objectFrom(json);
Object[] result = new Object[3];
result[0] = res.getCode();
result[1] = res.getContentType();
result[2] = res.getStream();
return result;
}
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 {
String content = o.toString();
if (base64 && content.contains("base64,")) content = content.split("base64,")[1];
return new ByteArrayInputStream(base64 ? Util.decode(content) : content.getBytes());
}
}
}