Merge pull request #13 from qaiu/dev

蓝奏云规则修改, 奶牛功能增强
This commit is contained in:
qaiu
2023-08-20 10:35:02 +08:00
committed by GitHub
30 changed files with 410 additions and 105 deletions

View File

@@ -1,4 +1,5 @@
# netdisk-fast-download
云盘解析服务 (nfd云解析)
预览地址 https://lz.qaiu.top
[![Java CI with Maven](https://github.com/qaiu/netdisk-fast-download/actions/workflows/maven.yml/badge.svg)](https://github.com/qaiu/netdisk-fast-download/actions/workflows/maven.yml)
@@ -6,6 +7,15 @@
[![vert.x](https://img.shields.io/badge/vert.x-4.4.1-blue)](https://vertx-china.github.io/)
[![GitHub release (latest by date)](https://img.shields.io/github/v/release/qaiu/netdisk-fast-download)](https://github.com/qaiu/netdisk-fast-download/releases/tag/0.1.6-releases)
## 项目介绍
网盘直链解析工具能把网盘分享下载链接转化为直链,已支持蓝奏云/奶牛快传/移动云云空间/小飞机盘/亿方云/123云盘等支持私密分享。
## 应用场景:
1. 游戏:使用本站工具可自动生成高速直流下载器,用于游戏客户端自动化高速下载安装、更新等。
2. 下载:可根据网盘分享的地址解析为直链,方便放到自己网站上供用户下载,节约服务器带宽和磁盘。
3. 音视频:可解析为音视频直链,可直接在网页上播放,高清,高速,节约服务器带宽和磁盘。
4. 图床:可支持图床。
## 网盘支持情况:
> 20230722 UC网盘解析失效需要登录

View File

@@ -157,8 +157,8 @@ public class CreateTable {
return sql.substring(0, sql.length() - 1) + ");\r\n";
}
public static void createTable(JDBCPool pool, String tableClassPath) {
Set<Class<?>> tableClassList = ReflectionUtil.getReflections(tableClassPath).getTypesAnnotatedWith(Table.class);
public static void createTable(JDBCPool pool) {
Set<Class<?>> tableClassList = ReflectionUtil.getReflections().getTypesAnnotatedWith(Table.class);
if (tableClassList.isEmpty()) LOGGER.info("Table model class not fount");
tableClassList.forEach(clazz -> {
String createTableSQL = getCreateTableSQL(clazz);

View File

@@ -92,7 +92,7 @@ public class JDBCPoolInit {
private void poolInitExecute(Promise<String> promise) {
// 初始化连接池
pool = JDBCPool.pool(vertx, dbConfig);
CreateTable.createTable(pool, dbConfig.getString("tableClassPath"));
CreateTable.createTable(pool);
promise.complete("init jdbc pool success");
}

View File

@@ -20,6 +20,7 @@
<slf4j.version>2.0.5</slf4j.version>
<commons-lang3.version>3.12.0</commons-lang3.version>
<jackson.version>2.14.2</jackson.version>
<logback.version>1.4.6</logback.version>
</properties>
<dependencyManagement>
@@ -39,7 +40,7 @@
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.4.6</version>
<version>${logback.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>

View File

@@ -1,6 +1,5 @@
package cn.qaiu.vx.core;
import cn.qaiu.vx.core.util.ConfigConstant;
import cn.qaiu.vx.core.util.ConfigUtil;
import cn.qaiu.vx.core.util.VertxHolder;
import cn.qaiu.vx.core.verticle.ReverseProxyVerticle;
@@ -18,6 +17,8 @@ import java.util.Calendar;
import java.util.Date;
import java.util.concurrent.locks.LockSupport;
import static cn.qaiu.vx.core.util.ConfigConstant.*;
/**
* vertx启动类 需要在主启动类完成回调
* <br>Create date 2021-05-07 10:26:54
@@ -108,10 +109,10 @@ public final class Deploy {
private void deployVerticle() {
tempVertx.close();
LOGGER.info("配置读取成功");
customConfig = globalConfig.getJsonObject(ConfigConstant.CUSTOM);
customConfig = globalConfig.getJsonObject(CUSTOM);
JsonObject vertxConfig = globalConfig.getJsonObject(ConfigConstant.VERTX);
Integer vertxConfigELPS = vertxConfig.getInteger(ConfigConstant.EVENT_LOOP_POOL_SIZE);
JsonObject vertxConfig = globalConfig.getJsonObject(VERTX);
Integer vertxConfigELPS = vertxConfig.getInteger(EVENT_LOOP_POOL_SIZE);
var vertxOptions = vertxConfigELPS == 0 ?
new VertxOptions() : new VertxOptions(vertxConfig);
@@ -122,10 +123,10 @@ public final class Deploy {
VertxHolder.init(vertx);
//配置保存在共享数据中
var sharedData = vertx.sharedData();
LocalMap<String, Object> localMap = sharedData.getLocalMap(ConfigConstant.LOCAL);
localMap.put(ConfigConstant.GLOBAL_CONFIG, globalConfig);
localMap.put(ConfigConstant.CUSTOM_CONFIG, customConfig);
localMap.put(ConfigConstant.SERVER, globalConfig.getJsonObject(ConfigConstant.SERVER));
LocalMap<String, Object> localMap = sharedData.getLocalMap(LOCAL);
localMap.put(GLOBAL_CONFIG, globalConfig);
localMap.put(CUSTOM_CONFIG, customConfig);
localMap.put(SERVER, globalConfig.getJsonObject(SERVER));
var future0 = vertx.createSharedWorkerExecutor("other-handle").executeBlocking(bch -> {
handle.handle(globalConfig);
bch.complete("other handle complete");
@@ -169,7 +170,7 @@ public final class Deploy {
* @return Deployment Options
*/
private DeploymentOptions getWorkDeploymentOptions(String name) {
return getWorkDeploymentOptions(name, customConfig.getInteger(ConfigConstant.ASYNC_SERVICE_INSTANCES));
return getWorkDeploymentOptions(name, customConfig.getInteger(ASYNC_SERVICE_INSTANCES));
}
private DeploymentOptions getWorkDeploymentOptions(String name, int ins) {

View File

@@ -0,0 +1,23 @@
package cn.qaiu.vx.core.annotaions;
import java.lang.annotation.*;
/**
* 拦截器配置注解
* 正则匹配拦截途径
*
* @author <a href="https://qaiu.top">QAIU</a>
*/
@Documented
@Inherited
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface InterceptorConfig {
String pattern() default "";
/**
* 注册顺序,数字越大越先注册
*/
int order() default 0;
}

View File

@@ -6,6 +6,7 @@ import cn.qaiu.vx.core.annotaions.RouteMapping;
import cn.qaiu.vx.core.annotaions.SockRouteMapper;
import cn.qaiu.vx.core.base.BaseHttpApi;
import cn.qaiu.vx.core.enums.MIMEType;
import cn.qaiu.vx.core.interceptor.Interceptor;
import cn.qaiu.vx.core.model.JsonResult;
import cn.qaiu.vx.core.util.*;
import io.vertx.core.Future;
@@ -22,6 +23,7 @@ import io.vertx.ext.web.RoutingContext;
import io.vertx.ext.web.handler.BodyHandler;
import io.vertx.ext.web.handler.CorsHandler;
import io.vertx.ext.web.handler.StaticHandler;
import io.vertx.ext.web.handler.TimeoutHandler;
import io.vertx.ext.web.handler.sockjs.SockJSHandler;
import io.vertx.ext.web.handler.sockjs.SockJSHandlerOptions;
import javassist.CtClass;
@@ -38,6 +40,7 @@ import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static cn.qaiu.vx.core.util.ConfigConstant.ROUTE_TIME_OUT;
import static io.vertx.core.http.HttpHeaders.*;
/**
@@ -62,10 +65,9 @@ public class RouterHandlerFactory implements BaseHttpApi {
private final String gatewayPrefix;
public RouterHandlerFactory(String routerScanAddress, String gatewayPrefix) {
Objects.requireNonNull(routerScanAddress, "The router package address scan is empty.");
public RouterHandlerFactory(String gatewayPrefix) {
Objects.requireNonNull(gatewayPrefix, "The gateway prefix is empty.");
reflections = ReflectionUtil.getReflections(routerScanAddress);
reflections = ReflectionUtil.getReflections();
this.gatewayPrefix = gatewayPrefix;
}
@@ -173,6 +175,8 @@ public class RouterHandlerFactory implements BaseHttpApi {
route.consumes(mineType);
}
// 设置默认超时
route.handler(TimeoutHandler.create(SharedDataUtil.getCustomConfig().getInteger(ROUTE_TIME_OUT)));
// 先执行拦截方法, 再进入业务请求
route.handler(interceptor);
route.handler(ctx -> handlerMethod(instance, method, ctx)).failureHandler(ctx -> {
@@ -234,10 +238,8 @@ public class RouterHandlerFactory implements BaseHttpApi {
private Handler<RoutingContext> getInterceptor() throws Throwable {
// 配置拦截
Class<?> interceptorClass = Class.forName(SharedDataUtil.getValueForCustomConfig("interceptorClassPath"));
Object handleInstance = ReflectionUtil.newWithNoParam(interceptorClass);
Method doHandle = interceptorClass.getMethod("doHandle");
// 反射调用
return CastUtil.cast(ReflectionUtil.invoke(doHandle, handleInstance));
Interceptor handleInstance = (Interceptor)ReflectionUtil.newWithNoParam(interceptorClass);
return handleInstance.doHandle();
}
/**

View File

@@ -3,11 +3,14 @@ package cn.qaiu.vx.core.util;
public interface ConfigConstant {
String CUSTOM = "custom";
String VERTX = "vertx";
String EVENT_LOOP_POOL_SIZE = "eventLoopPoolSize";
String LOCAL = "local";
String SERVER = "server";
String GLOBAL_CONFIG = "globalConfig";
String CUSTOM_CONFIG = "customConfig";
String ASYNC_SERVICE_INSTANCES = "asyncServiceInstances";
String IGNORES_REG="ignoresReg";
String BASE_LOCATIONS="baseLocations";
String ROUTE_TIME_OUT="routeTimeOut";
}

View File

@@ -24,6 +24,8 @@ import java.net.URL;
import java.text.ParseException;
import java.util.*;
import static cn.qaiu.vx.core.util.ConfigConstant.BASE_LOCATIONS;
/**
* 基于org.reflection和javassist的反射工具包
* 通过包扫描实现路由地址的注解映射
@@ -33,6 +35,16 @@ import java.util.*;
*/
public final class ReflectionUtil {
/**
* 以默认配置的基础包路径获取反射器
*
* @return Reflections object
*/
public static Reflections getReflections() {
return getReflections(SharedDataUtil.getStringForCustomConfig(BASE_LOCATIONS));
}
/**
* 获取反射器
*
@@ -48,6 +60,7 @@ public final class ReflectionUtil {
} else {
packageAddressList = Collections.singletonList(packageAddress);
}
return getReflections(packageAddressList);
}
@@ -70,10 +83,11 @@ public final class ReflectionUtil {
// 发现注解api层 没有继承父类时 这里反射一直有问题(Scanner SubTypesScanner was not configured)
// 因此这里需要手动配置各种Scanner扫描器 -- https://blog.csdn.net/qq_29499107/article/details/106889781
configurationBuilder.setScanners(
Scanners.SubTypes.filterResultsBy(s -> true), //允许getAllTypes获取所有Object的子类, 不设置为false则 getAllTypes 会报错.默认为true.
Scanners.SubTypes.filterResultsBy(s -> true), //允许getAllTypes获取所有Object的子类, 不设置为false则 getAllTypes
// 会报错.默认为true.
new MethodParameterNamesScanner(), //设置方法参数名称 扫描器,否则调用getConstructorParamNames 会报错
Scanners.MethodsAnnotated, //设置方法注解 扫描器, 否则getConstructorsAnnotatedWith,getMethodsAnnotatedWith 会报错
new MemberUsageScanner(), //设置 member 扫描器,否则 getMethodUsage 会报错, 不推荐使用,有可能会报错 Caused by: java.lang.ClassCastException: javassist.bytecode.InterfaceMethodrefInfo cannot be cast to javassist.bytecode.MethodrefInfo
new MemberUsageScanner(), //设置 member 扫描器,否则 getMethodUsage 会报错
Scanners.TypesAnnotated //设置类注解 扫描器 ,否则 getTypesAnnotatedWith 会报错
);
@@ -98,7 +112,8 @@ public final class ReflectionUtil {
MethodInfo methodInfo = cm.getMethodInfo();
CtClass[] parameterTypes = cm.getParameterTypes();
CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute.getAttribute(LocalVariableAttribute.tag);
LocalVariableAttribute attr =
(LocalVariableAttribute) codeAttribute.getAttribute(LocalVariableAttribute.tag);
boolean flag = true;
boolean flag2 = cm.getModifiers() - 1 != AccessFlag.STATIC;
@@ -110,7 +125,8 @@ public final class ReflectionUtil {
continue;
}
flag = false;
paramMap.put(attr.variableName(j + (flag2 ? 1 : 0)), Pair.of(parameterAnnotations[j - k], parameterTypes[j - k]));
paramMap.put(attr.variableName(j + (flag2 ? 1 : 0)), Pair.of(parameterAnnotations[j - k],
parameterTypes[j - k]));
}
} catch (NotFoundException e) {
e.printStackTrace();
@@ -214,7 +230,8 @@ public final class ReflectionUtil {
if (ctClass.isPrimitive() || "java.util.Date".equals(ctClass.getName())) {
return true;
}
return ctClass.getName().matches("^java\\.lang\\.((Boolean)|(Character)|(Byte)|(Short)|(Integer)|(Long)|(Float)|(Double)|(String))$");
return ctClass.getName().matches("^java\\.lang\\.((Boolean)|(Character)|(Byte)|(Short)|(Integer)|(Long)|" +
"(Float)|(Double)|(String))$");
}
/**
@@ -238,7 +255,8 @@ public final class ReflectionUtil {
* @throws InstantiationException InstantiationException
* @throws IllegalAccessException IllegalAccessException
*/
public static <T> T newWithNoParam(Class<T> handler) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
public static <T> T newWithNoParam(Class<T> handler) throws NoSuchMethodException, InvocationTargetException,
InstantiationException, IllegalAccessException {
return handler.getConstructor().newInstance();
}

View File

@@ -32,11 +32,11 @@ public class SharedDataUtil {
return (JsonObject) localMap.get(key);
}
public static JsonObject getJsonObjectForCustomConfig(String key) {
return getJsonConfig("customConfig").getJsonObject(key);
public static JsonObject getCustomConfig() {
return getJsonConfig("customConfig");
}
public static String getJsonStringForCustomConfig(String key) {
public static String getStringForCustomConfig(String key) {
return getJsonConfig("customConfig").getString(key);
}

View File

@@ -23,7 +23,6 @@ public class RouterVerticle extends AbstractVerticle {
private static final int port = SharedDataUtil.getValueForServerConfig("port");
private static final Router router = new RouterHandlerFactory(
SharedDataUtil.getJsonStringForCustomConfig("routerLocations"),
SharedDataUtil.getJsonStringForServerConfig("contextPath")).createRouter();
private static final JsonObject globalConfig = SharedDataUtil.getJsonConfig("globalConfig");

View File

@@ -3,7 +3,6 @@ package cn.qaiu.vx.core.verticle;
import cn.qaiu.vx.core.annotaions.Service;
import cn.qaiu.vx.core.base.BaseAsyncService;
import cn.qaiu.vx.core.util.ReflectionUtil;
import cn.qaiu.vx.core.util.SharedDataUtil;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.Promise;
import io.vertx.serviceproxy.ServiceBinder;
@@ -27,8 +26,7 @@ public class ServiceVerticle extends AbstractVerticle {
private static final Set<Class<?>> handlers;
static {
String handlerLocations = SharedDataUtil.getJsonStringForCustomConfig("handlerLocations");
Reflections reflections = ReflectionUtil.getReflections(handlerLocations);
Reflections reflections = ReflectionUtil.getReflections();
handlers = reflections.getTypesAnnotatedWith(Service.class);
}

View File

@@ -7,6 +7,8 @@ import io.vertx.core.json.JsonArray;
import io.vertx.ext.web.RoutingContext;
import lombok.extern.slf4j.Slf4j;
import static cn.qaiu.vx.core.util.ConfigConstant.IGNORES_REG;
/**
* 默认拦截器实现
* 校验用户是否合法 <br>
@@ -15,7 +17,8 @@ import lombok.extern.slf4j.Slf4j;
@Slf4j
public class DefaultInterceptor implements Interceptor, BaseHttpApi {
private final JsonArray ignores = SharedDataUtil.getJsonArrayForCustomConfig("ignoresReg");
protected final JsonArray ignores = SharedDataUtil.getJsonArrayForCustomConfig(IGNORES_REG);
@Override
public void beforeHandle(RoutingContext ctx) {
@@ -23,7 +26,7 @@ public class DefaultInterceptor implements Interceptor, BaseHttpApi {
}
@Override
public void afterHandle(RoutingContext context) {
public void afterHandle(RoutingContext ctx) {
}
}

View File

@@ -0,0 +1,23 @@
package cn.qaiu.lz.common.model;
import cn.qaiu.lz.common.util.SnowflakeIdWorker;
import lombok.Data;
import java.util.Date;
@Data
abstract public class BaseModel {
public static final long serialVersionUID = 1L;
private String id = String.valueOf(SnowflakeIdWorker.idWorker().nextId());
private String createBy;
private Date createTime;
private String updateBy;
private Date updateTime;
}

View File

@@ -0,0 +1,16 @@
package cn.qaiu.lz.common.model;
import io.vertx.core.MultiMap;
public class FileInfo extends BaseModel {
private String fileName;
private String fileType;
private Long fileSize;
private String download;
private MultiMap header;
}

View File

@@ -0,0 +1,5 @@
package cn.qaiu.lz.common.model;
public class ParserInfo {
}

View File

@@ -23,7 +23,7 @@ public interface IPanTool {
static IPanTool shareURLPrefixMatching(String url, String pwd) {
if (url.startsWith(CowTool.SHARE_URL_PREFIX)) {
if (url.contains(CowTool.LINK_KEY)) {
return new CowTool(url, pwd);
} else if (url.startsWith(EcTool.SHARE_URL_PREFIX)) {
return new EcTool(url, pwd);
@@ -35,7 +35,7 @@ public interface IPanTool {
return new YeTool(url, pwd);
} else if (url.startsWith(FjTool.SHARE_URL_PREFIX)) {
return new FjTool(url, pwd);
} else if (url.contains("lanzou")) {
} else if (url.contains(LzTool.LINK_KEY)) {
return new LzTool(url, pwd);
}

View File

@@ -18,6 +18,8 @@ public class CowTool extends PanBase implements IPanTool {
private static final String API_REQUEST_URL = "https://cowtransfer.com/core/api/transfer/share";
public static final String SHARE_URL_PREFIX = "https://cowtransfer.com/s/";
public static final String LINK_KEY = "cowtransfer.com/s/";
public CowTool(String key, String pwd) {
super(key, pwd);
}
@@ -30,8 +32,16 @@ public class CowTool extends PanBase implements IPanTool {
if ("success".equals(resJson.getString("message")) && resJson.containsKey("data")) {
JsonObject dataJson = resJson.getJsonObject("data");
String guid = dataJson.getString("guid");
String fileId = dataJson.getJsonObject("firstFile").getString("id");
String url2 = API_REQUEST_URL + "/download?transferGuid=" + guid + "&fileId=" + fileId;
StringBuilder url2Build = new StringBuilder(API_REQUEST_URL + "/download?transferGuid=" + guid);
if (dataJson.getBoolean("zipDownload")) {
// &title=xxx
JsonObject firstFolder = dataJson.getJsonObject("firstFolder");
url2Build.append("&title=").append(firstFolder.getString("title"));
} else {
String fileId = dataJson.getJsonObject("firstFile").getString("id");
url2Build.append("&fileId=").append(fileId);
}
String url2 = url2Build.toString();
client.getAbs(url2).send().onSuccess(res2 -> {
JsonObject res2Json = res2.bodyAsJsonObject();
if ("success".equals(res2Json.getString("message")) && res2Json.containsKey("data")) {

View File

@@ -2,6 +2,7 @@ package cn.qaiu.lz.common.parser.impl;
import cn.qaiu.lz.common.parser.IPanTool;
import cn.qaiu.lz.common.parser.PanBase;
import cn.qaiu.lz.common.util.JsExecUtils;
import cn.qaiu.vx.core.util.VertxHolder;
import io.vertx.core.Future;
import io.vertx.core.MultiMap;
@@ -9,7 +10,10 @@ import io.vertx.core.Promise;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.client.WebClient;
import io.vertx.ext.web.client.WebClientOptions;
import org.openjdk.nashorn.api.scripting.ScriptObjectMirror;
import javax.script.ScriptException;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -23,10 +27,49 @@ public class LzTool extends PanBase implements IPanTool {
public static final String SHARE_URL_PREFIX = "https://wwwa.lanzoui.com";
public static final String LINK_KEY = "lanzou";
public LzTool(String key, String pwd) {
super(key, pwd);
}
/*
var wsk_sign = 'c20230818';
var aihidcms = 'Fn5L';
var iucjdsd = '';
var ws_sign = 'c20230818';
var sasign = 'B2EBPw8_bBDVRWFdoAzMGOlI5ATwEbVFgV2NVZwVhATYILld0WjoAZQhoVDsEYlZjBm4BNgVoVGcHMQ_c_c';
var ajaxdata = '?ctdf';
$.ajax({
type : 'post',
url : '/ajaxm.php',
//b data : { 'action':'downprocess','signs':ajaxdata,'sign':'w},
data : { 'action':'downprocess','signs':ajaxdata,'sign':sasign,'websign':iucjdsd,'websignkey':aihidcms,'ves':1 },
//b data : { 'action':'downprocess','signs':ajaxdata,'sign':'','websign':ws_sign,'websignkey':wsk_sign,'ves':1 },
dataType : 'json',
success:function(msg){
var date = msg;
if(date.zt == '1'){
$("#tourl").html("<a href="+date.dom+"/file/"+ date.url +" target=_blank rel=noreferrer><span class=txt>电信下载</span><span class='txt txtc'>联通下载</span><span class=txt>普通下载</span></a>");
setTimeout('$("#outime").css("display","block");',1800000);
}else{
$("#tourl").html("网页超时,请刷新");
};
},
error:function(){
$("#tourl").html("获取失败,请刷新");
}
});
*/
/**
* 蓝奏云解析器
*
* @return url String
*/
@SuppressWarnings("unchecked")
public Future<String> parse() {
String sUrl = key.startsWith("https://") ? key : SHARE_URL_PREFIX + "/" + key;
@@ -37,35 +80,66 @@ public class LzTool extends PanBase implements IPanTool {
// 匹配iframe
Pattern compile = Pattern.compile("src=\"(/fn\\?[a-zA-Z\\d_+/=]{16,})\"");
Matcher matcher = compile.matcher(html);
// 没有Iframe说明是加密分享, 匹配sign通过密码请求下载页面
if (!matcher.find()) {
// 没有Iframe说明是加密分享, 匹配sign通过密码请求下载页面
Pattern compile2 = Pattern.compile("sign=(\\w{16,})");
Matcher matcher2 = compile2.matcher(html);
if (!matcher2.find()) {
fail(sUrl + ": sign正则匹配失败, 可能分享已失效");
// 处理一下JS
String jsText = getJsText(html);
if (jsText == null) {
fail(SHARE_URL_PREFIX + " -> " + sUrl + ": js脚本匹配失败, 可能分享已失效");
return;
}
jsText = jsText.replace("document.getElementById('pwd').value", "\"" + pwd + "\"");
jsText = jsText.substring(0, jsText.indexOf("document.getElementById('rpt')"));
try {
ScriptObjectMirror scriptObjectMirror = JsExecUtils.executeDynamicJs(jsText, "down_p");
getDownURL(promise, sUrl, client, (Map<String, String>) scriptObjectMirror.get("data"));
} catch (ScriptException | NoSuchMethodException e) {
fail(e, "js引擎执行失败");
return;
}
String sign = matcher2.group(1);
getDownURL(promise, sUrl, client, sign);
return;
}
String iframePath = matcher.group(1);
client.getAbs(SHARE_URL_PREFIX + iframePath).send().onSuccess(res2 -> {
String html2 = res2.bodyAsString();
System.out.println(html);
Matcher matcher2 = Pattern.compile("'sign'\s*:\s*'(\\w+)'").matcher(html2);
if (!matcher2.find()) {
fail(SHARE_URL_PREFIX + iframePath + " -> " + sUrl + ": sign正则匹配失败, 可能分享已失效");
// 去TMD正则
// Matcher matcher2 = Pattern.compile("'sign'\s*:\s*'(\\w+)'").matcher(html2);
String jsText = getJsText(html2);
if (jsText == null) {
fail(SHARE_URL_PREFIX + iframePath + " -> " + sUrl + ": js脚本匹配失败, 可能分享已失效");
return;
}
String sign = matcher2.group(1);
getDownURL(promise, sUrl, client, sign);
try {
ScriptObjectMirror scriptObjectMirror = JsExecUtils.executeDynamicJs(jsText, null);
getDownURL(promise, sUrl, client, (Map<String, String>) scriptObjectMirror.get("data"));
} catch (ScriptException | NoSuchMethodException e) {
fail(e, "js引擎执行失败");
}
}).onFailure(handleFail(SHARE_URL_PREFIX));
}).onFailure(handleFail(sUrl));
return promise.future();
}
private void getDownURL(Promise<String> promise, String key, WebClient client, String sign) {
private String getJsText(String html) {
String jsTagStart = "<script type=\"text/javascript\">";
String jsTagEnd = "</script>";
int index = html.indexOf(jsTagStart);
if (index == -1) {
return null;
}
int startPos = index + jsTagStart.length();
int endPos = html.indexOf(jsTagEnd, startPos);
return html.substring(startPos, endPos);
}
private void getDownURL(Promise<String> promise, String key, WebClient client, Map<String, ?> signMap) {
MultiMap map = MultiMap.caseInsensitiveMultiMap();
signMap.forEach((k, v) -> {
map.set(k, v.toString());
});
MultiMap headers = MultiMap.caseInsensitiveMultiMap();
var userAgent2 = "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, " +
"like " +
@@ -79,8 +153,7 @@ public class LzTool extends PanBase implements IPanTool {
String url = SHARE_URL_PREFIX + "/ajaxm.php";
client.postAbs(url).putHeaders(headers).sendForm(MultiMap
.caseInsensitiveMultiMap()
.set("action", "downprocess")
.set("sign", sign).set("p", pwd)).onSuccess(res2 -> {
.setAll(map)).onSuccess(res2 -> {
JsonObject urlJson = res2.bodyAsJsonObject();
if (urlJson.getInteger("zt") != 1) {
fail(urlJson.getString("inf"));

View File

@@ -8,12 +8,16 @@ import java.util.Map;
public class CommonUtils {
public static String adaptShortPaths(String urlPrefix, String url) {
if (!url.startsWith(urlPrefix)) {
url = urlPrefix + url;
}
if (url.endsWith(".html")) {
url = url.substring(0, url.length() - 5);
}
String prefix = "https://";
if (!url.startsWith(urlPrefix) && url.startsWith(prefix)) {
urlPrefix = urlPrefix.substring(prefix.length());
return url.substring(url.indexOf(urlPrefix) + urlPrefix.length());
} else if (!url.startsWith(urlPrefix)) {
url = urlPrefix + url;
}
return url.substring(urlPrefix.length());
}

View File

@@ -1,24 +1,31 @@
package cn.qaiu.lz.common.util;
import org.apache.commons.lang3.StringUtils;
import org.openjdk.nashorn.api.scripting.ScriptObjectMirror;
import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
/**
* 执行Js脚本
*
* @author <a href="https://qaiu.top">QAIU</a>
* @date 2023/7/29 17:35
*/
public class JsExecUtils {
private static final String JS_PATH = "/js/ye123.js";
private static Invocable inv;
private static final String JS_PATH = "js/ye123.js";
private static final String LZ_JS_PATH = "js/lz.js";
private static final String RES_PATH;
private static final Invocable inv;
// 初始化脚本引擎
static {
@@ -29,9 +36,9 @@ public class JsExecUtils {
if (resource == null) {
throw new RuntimeException("js resource path is null");
}
String path = resource.getPath();
String reader = path + JS_PATH;
try (FileReader fReader = new FileReader(reader)){
RES_PATH = resource.getPath();
String reader = RES_PATH + JS_PATH;
try (FileReader fReader = new FileReader(reader)) {
engine.eval(fReader);
fReader.close();
inv = (Invocable) engine;
@@ -43,8 +50,40 @@ public class JsExecUtils {
/**
* 调用js文件
*/
public static ScriptObjectMirror executeJs(String functionName, Object... args) throws ScriptException, NoSuchMethodException {
//调用js中的方法
public static ScriptObjectMirror executeJs(String functionName, Object... args) throws ScriptException,
NoSuchMethodException {
//调用js中的函数
return (ScriptObjectMirror) inv.invokeFunction(functionName, args);
}
/**
* 调用执行蓝奏云js文件
*/
public static ScriptObjectMirror executeDynamicJs(String jsText, String funName) throws ScriptException,
NoSuchMethodException {
ScriptEngineManager engineManager = new ScriptEngineManager();
ScriptEngine engine = engineManager.getEngineByName("JavaScript"); // 得到脚本引擎
try {
//获取文件所在的相对路径
Path path;
try {
path = Paths.get(RES_PATH + LZ_JS_PATH);
} catch (RuntimeException ioe) {
path = Paths.get(RES_PATH.substring(1) + LZ_JS_PATH);
}
String jsContent = Files.readString(path) + "\n" + jsText;
engine.eval(jsContent);
Invocable inv = (Invocable) engine;
//调用js中的函数
if (StringUtils.isNotEmpty(funName)) {
inv.invokeFunction(funName);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
return (ScriptObjectMirror) engine.get("signObj");
}
}

View File

@@ -1,4 +1,4 @@
package cn.qaiu.vx.core.util;
package cn.qaiu.lz.common.util;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
@@ -30,6 +30,8 @@ public class SnowflakeIdWorker {
// ==============================Fields===========================================
//开始时间截 (2021-01-01)
private static final long EPOCH = 1609459200000L;
/**
* 机器id所占的位数
*/
@@ -133,9 +135,7 @@ public class SnowflakeIdWorker {
//时间截向左移22位(5+5+12)
long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
//开始时间截 (2021-01-01)
long twepoch = 1609459200000L;
return ((timestamp - twepoch) << timestampLeftShift) //
return ((timestamp - EPOCH) << timestampLeftShift) //
| (datacenterId << datacenterIdShift) //
| (workerId << sequenceBits) //
| sequence;
@@ -220,24 +220,4 @@ public class SnowflakeIdWorker {
}
return snowflakeIdWorkerCluster;
}
//==============================Test=============================================
/**
* 测试
*/
public static void main(String[] args) {
final SnowflakeIdWorker snowflakeIdWorkerCluster = idWorkerCluster(0, 1);
final SnowflakeIdWorker idWorker = idWorker();
for (int i = 0; i < 100; i++) {
long id = idWorker.nextId();
System.out.println(Long.toBinaryString(id));
System.out.println(id);
System.out.println("------------");
id = snowflakeIdWorkerCluster.nextId();
System.out.println(Long.toBinaryString(id));
System.out.println(id);
System.out.println("------------\n");
}
}
}

View File

@@ -1,7 +1,7 @@
package cn.qaiu.lz.web.http;
import cn.qaiu.lz.common.parser.IPanTool;
import cn.qaiu.lz.common.parser.impl.*;
import cn.qaiu.lz.common.parser.impl.EcTool;
import cn.qaiu.lz.web.model.SysUser;
import cn.qaiu.lz.web.service.UserService;
import cn.qaiu.vx.core.annotaions.RouteHandler;

View File

@@ -5,6 +5,8 @@ import cn.qaiu.lz.web.service.UserService;
import cn.qaiu.vx.core.annotaions.Service;
import io.vertx.core.Future;
import java.util.concurrent.TimeUnit;
/**
* lz-web
* <br>Create date 2021/8/27 14:09
@@ -17,6 +19,11 @@ public class UserServiceImpl implements UserService {
@Override
public Future<String> login(SysUser user) {
try {
TimeUnit.SECONDS.sleep(6);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return Future.succeededFuture("111");
}
}

View File

@@ -19,19 +19,21 @@ custom:
# 异步服务线程数
asyncServiceInstances: 4
# server路由(controller层)所在包路径
routerLocations: cn.qaiu.lz.web.http
baseLocations: cn.qaiu.lz
# 路由处理默认超时时间(毫秒)
routeTimeOut: 15000
# 拦截器包路径
interceptorClassPath: cn.qaiu.lz.common.interceptorImpl.DefaultInterceptor
# server层包路径
handlerLocations: cn.qaiu.lz.web.service
# 匹配规则
# 拦截器匹配规则
ignoresReg:
- .*/login$
- .*/test.*$
# 实体类包路径匹配正则
# 参数注入的实体类包路径匹配正则 (防止同名类引发歧义)
entityPackagesReg:
- ^cn\.qaiu\.lz\.web\.model\..*
# 数据源配置
dataSource:
provider_class: io.vertx.ext.jdbc.spi.impl.HikariCPDataSourceProvider

View File

@@ -46,15 +46,14 @@ Content-Disposition: form-data; name="email"
--WebAppBoundary
Content-Disposition: form-data; name="joinProToken"
--WebAppBoundary--
###
https://cowtransfer.com/core/api/transfer/share/download?transferGuid=eb9df924-7b29-496b-8147-96762fc81d28&title=spring-play
###
git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch web-service/src/main/resources/http-tools/test.http' --prune-empty --tag-name-filter cat -- --all
git push origin master --force
rmdir .git/refs/original/
git reflog expire --expire=now --all
git gc --prune=now
git gc --aggressive --prune=now
https://cowtransfer.com/core/api/transfer/share/download?transferGuid=
###
https://cowtransfer.com/core/api/transfer/share/download?transferGuid=eb9df924-7b29-496b-8147-96762fc81d28

View File

@@ -24,4 +24,13 @@ https://developer.lanzoug.com/file/?VDJbZVxtADFSWwY+U2YHa1FuU2tTYgBnBnUGZFNmWylS
###
https://developer.lanzoug.com/file/?VTNVa1tqAjMFDAM7BDEAbAE+U2tfbgZhBnVbOQUwVCYEb1IoAToCNwQhVnRXLlcyVWAEdl9uVzkEbFYxVm5VeVVlVSxbNwJ4BWADeAQyAGgBNVN4X3oGbQZxW3sFP1Q8BGhSYAEDAj8ENlY9VzJXZ1U3BDFfMldlBDFWaVY9VXJVM1VxWzsCZwVlA2QEYAAwAWtTYF8wBiIGcVstBWRUZwQ0UjcBbwJ5BGJWNVcsV2RVOgQuX2NXZgQ2VjJWMlVhVWdVNlswAm8FagMxBGAANgE6UzdfYwZgBjFbbAU6VGwEZVIyAWQCZQRkVjZXMFdmVTcENV8uVy8EalYgVixVIVUmVWdbdAI/BTcDaARhADEBblNvXzQGPQY5W3sFLVQ8BGlSYAE6AmsEY1Y2VztXY1U/BDFfM1dnBDRWZFYkVXpVc1VkW2oCIQVuA2QEZgA5AW5TZl8wBjYGMFtkBWFUcwRxUnUBKwJrBGNWNlc7V2NVPwQxXzJXZQQzVmdWLFUhVTxVcls7AmcFYgNnBH4AMwFoU2RfLgY1BjVbawV3VGIEPA==
### 20230819新规则
POST /ajaxm.php
# var wsk_sign = 'c20230818';
# var aihidcms = 'J5Nh';
# var iucjdsd = '';
# var ws_sign = 'c20230818';
# var sasign = 'AGZQbgk4UGEDCgo1ATEGOlY_aBTlSNVRiV2gEMlA1WmkBJ1R3AWFUMVY2VDsDZQE0Vj4CMgNsADdXZw_c_c';
# var ajaxdata = '?ctdf';
data : { 'action':'downprocess','signs':ajaxdata,'sign':sasign,'websign':iucjdsd,'websignkey':aihidcms,'ves':1 }

View File

@@ -28,6 +28,10 @@ GET http://127.0.0.1:6400/cow/e4f41b51b5da4f
# @no-redirect
GET http://127.0.0.1:6400/parser?url=https://cowtransfer.com/s/9a644fe3e3a748
### 奶牛
# @no-redirect
GET http://127.0.0.1:6400/parser?url=https://goldrepo.cowtransfer.com/s/026a638795634b
### 移动云空间 https://www.ecpan.cn/web/#/yunpanProxy?path=%2F%23%2Fdrive%2Foutside&data=81027a5c99af5b11ca004966c945cce6W9Bf2&isShare=1
# @no-redirect
GET http://127.0.0.1:6400/parser?url=https://www.ecpan.cn/web//yunpanProxy?path=%2F%23%2Fdrive%2Foutside&data=81027a5c99af5b11ca004966c945cce6W9Bf2&isShare=1
@@ -94,6 +98,6 @@ GET http://127.0.0.1:6400/ye/iaKtVv-qOECd
GET http://127.0.0.1:6400/parser?url=https://www.123pan.com/s/iaKtVv-6OECd.html&pwd=DcGe
###
POST http://127.0.0.1:6400/login1
POST http://127.0.0.1:6400/login

View File

@@ -0,0 +1,46 @@
/**
* 蓝奏云解析器js签名获取工具
*/
var signObj;
var $, jQuery;
$ = jQuery = function () {
return new jQuery.fn.init();
}
jQuery.fn = jQuery.prototype = {
init: function () {
return {
focus: function (a) {
},
keyup: function(a) {
},
ajax: function (obj) {
signObj = obj
}
}
},
}
jQuery.fn.init.prototype = jQuery.fn;
// 伪装jquery.ajax函数获取关键数据
$.ajax = function (obj) {
signObj = obj
}
var document = {
getElementById: function (v) {
return {
value: 'v'
}
},
}

View File

@@ -0,0 +1,30 @@
package cn.qaiu.vx.core.util;
import cn.qaiu.lz.common.util.SnowflakeIdWorker;
import org.junit.Test;
public class SnowflakeIdWorkerTest {
@Test
public void idWorker() {
final SnowflakeIdWorker idWorker = SnowflakeIdWorker.idWorker();
for (int i = 0; i < 100; i++) {
long id = idWorker.nextId();
System.out.println(Long.toBinaryString(id));
System.out.println(id);
System.out.println("------------");
}
}
@Test
public void idWorkerCluster() {
final SnowflakeIdWorker snowflakeIdWorkerCluster = SnowflakeIdWorker.idWorkerCluster(0, 1);
for (int i = 0; i < 100; i++) {
long id = snowflakeIdWorkerCluster.nextId();
System.out.println(Long.toBinaryString(id));
System.out.println(id);
System.out.println("------------\n");
}
}
}