代码结构优化, 异常处理优化

This commit is contained in:
QAIU
2023-08-08 11:34:32 +08:00
parent facf9b645e
commit 7917870c6b
12 changed files with 150 additions and 156 deletions

View File

@@ -8,15 +8,15 @@ public interface IPanTool {
static IPanTool typeMatching(String type, String key, String pwd) { static IPanTool typeMatching(String type, String key, String pwd) {
return switch (type) { return switch (type) {
case "lz" -> new LzTool(); case "lz" -> new LzTool(key, pwd);
case "cow" -> new CowTool(); case "cow" -> new CowTool(key, pwd);
case "ec" -> new EcTool(); case "ec" -> new EcTool(key, pwd);
case "fc" -> new FcTool(); case "fc" -> new FcTool(key, pwd);
case "uc" -> new UcTool(); case "uc" -> new UcTool(key, pwd);
case "ye" -> new YeTool(key, pwd); case "ye" -> new YeTool(key, pwd);
case "fj" -> new FjTool(); case "fj" -> new FjTool(key, pwd);
default -> { default -> {
throw new IllegalArgumentException("未知分享类型"); throw new UnsupportedOperationException("未知分享类型");
} }
}; };
} }
@@ -24,22 +24,22 @@ public interface IPanTool {
static IPanTool shareURLPrefixMatching(String url, String pwd) { static IPanTool shareURLPrefixMatching(String url, String pwd) {
if (url.startsWith(CowTool.SHARE_URL_PREFIX)) { if (url.startsWith(CowTool.SHARE_URL_PREFIX)) {
return new CowTool(); return new CowTool(url, pwd);
} else if (url.startsWith(EcTool.SHARE_URL_PREFIX)) { } else if (url.startsWith(EcTool.SHARE_URL_PREFIX)) {
return new EcTool(); return new EcTool(url, pwd);
} else if (url.startsWith(FcTool.SHARE_URL_PREFIX0)) { } else if (url.startsWith(FcTool.SHARE_URL_PREFIX0)) {
return new FcTool(); return new FcTool(url, pwd);
} else if (url.startsWith(UcTool.SHARE_URL_PREFIX)) { } else if (url.startsWith(UcTool.SHARE_URL_PREFIX)) {
return new UcTool(); return new UcTool(url, pwd);
} else if (url.startsWith(YeTool.SHARE_URL_PREFIX)) { } else if (url.startsWith(YeTool.SHARE_URL_PREFIX)) {
return new YeTool(url, pwd); return new YeTool(url, pwd);
} else if (url.startsWith(FjTool.SHARE_URL_PREFIX)) { } else if (url.startsWith(FjTool.SHARE_URL_PREFIX)) {
return new FjTool(); return new FjTool(url, pwd);
} else if (url.contains("lanzou")) { } else if (url.contains("lanzou")) {
return new LzTool(); return new LzTool(url, pwd);
} }
throw new IllegalArgumentException("未知分享类型"); throw new UnsupportedOperationException("未知分享类型");
} }
} }

View File

@@ -1,14 +1,22 @@
package cn.qaiu.lz.common.parser; package cn.qaiu.lz.common.parser;
import cn.qaiu.vx.core.util.VertxHolder;
import io.vertx.core.Handler; import io.vertx.core.Handler;
import io.vertx.core.Promise; import io.vertx.core.Promise;
import io.vertx.ext.web.client.WebClient;
import io.vertx.ext.web.client.WebClientOptions;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
public abstract class PanBase { public abstract class PanBase {
protected Logger log = LoggerFactory.getLogger(this.getClass());
protected Promise<String> promise = Promise.promise(); protected Promise<String> promise = Promise.promise();
protected Logger log = LoggerFactory.getLogger(this.getClass());
protected WebClient client = WebClient.create(VertxHolder.getVertxInstance());
protected WebClient clientNoRedirects = WebClient.create(VertxHolder.getVertxInstance(), OPTIONS);
private static final WebClientOptions OPTIONS = new WebClientOptions().setFollowRedirects(false);
protected String key; protected String key;
protected String pwd; protected String pwd;
@@ -19,15 +27,27 @@ public abstract class PanBase {
} }
protected void fail(Throwable t, String errorMsg, Object... args) { protected void fail(Throwable t, String errorMsg, Object... args) {
String s = String.format(errorMsg.replaceAll("\\{}", "%s"), args); try {
log.error("解析异常: " + s, t.fillInStackTrace()); String s = String.format(errorMsg.replaceAll("\\{}", "%s"), args);
promise.fail(this.getClass().getSimpleName() + ": 解析异常: " + s + " -> " + t); log.error("解析异常: " + s, t.fillInStackTrace());
promise.fail(this.getClass().getSimpleName() + ": 解析异常: " + s + " -> " + t);
} catch (Exception e) {
log.error("ErrorMsg format fail. The parameter has been discarded", e);
log.error("解析异常: " + errorMsg, t.fillInStackTrace());
promise.fail(this.getClass().getSimpleName() + ": 解析异常: " + errorMsg + " -> " + t);
}
} }
protected void fail(String errorMsg, Object... args) { protected void fail(String errorMsg, Object... args) {
String s = String.format(errorMsg.replaceAll("\\{}", "%s"), args); try {
log.error("解析异常: " + s); String s = String.format(errorMsg.replaceAll("\\{}", "%s"), args);
promise.fail(this.getClass().getSimpleName() + " - 解析异常: " + s); log.error("解析异常: " + s);
promise.fail(this.getClass().getSimpleName() + " - 解析异常: " + s);
} catch (Exception e) {
log.error("ErrorMsg format fail. The parameter has been discarded", e);
log.error("解析异常: " + errorMsg);
promise.fail(this.getClass().getSimpleName() + " - 解析异常: " + errorMsg);
}
} }
protected Handler<Throwable> handleFail(String errorMsg) { protected Handler<Throwable> handleFail(String errorMsg) {

View File

@@ -1,14 +1,10 @@
package cn.qaiu.lz.common.parser.impl; package cn.qaiu.lz.common.parser.impl;
import cn.qaiu.lz.common.parser.IPanTool; import cn.qaiu.lz.common.parser.IPanTool;
import cn.qaiu.lz.common.parser.PanBase;
import cn.qaiu.lz.common.util.CommonUtils; import cn.qaiu.lz.common.util.CommonUtils;
import cn.qaiu.lz.common.util.PanExceptionUtils;
import cn.qaiu.vx.core.util.VertxHolder;
import io.vertx.core.Future; import io.vertx.core.Future;
import io.vertx.core.Promise;
import io.vertx.core.json.JsonObject; import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.client.WebClient;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
/** /**
@@ -17,17 +13,19 @@ import org.apache.commons.lang3.StringUtils;
* @author <a href="https://qaiu.top">QAIU</a> * @author <a href="https://qaiu.top">QAIU</a>
* @date 2023/4/21 21:19 * @date 2023/4/21 21:19
*/ */
@Slf4j public class CowTool extends PanBase implements IPanTool {
public class CowTool implements IPanTool {
private static final String API_REQUEST_URL = "https://cowtransfer.com/core/api/transfer/share"; 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 SHARE_URL_PREFIX = "https://cowtransfer.com/s/";
public Future<String> parse(String data, String code) { public CowTool(String key, String pwd) {
Promise<String> promise = Promise.promise(); super(key, pwd);
WebClient client = WebClient.create(VertxHolder.getVertxInstance()); }
String key = CommonUtils.adaptShortPaths(SHARE_URL_PREFIX, data);
client.getAbs(API_REQUEST_URL + "?uniqueUrl=" + key).send().onSuccess(res -> { public Future<String> parse() {
key = CommonUtils.adaptShortPaths(SHARE_URL_PREFIX, key);
String url = API_REQUEST_URL + "?uniqueUrl=" + key;
client.getAbs(url).send().onSuccess(res -> {
JsonObject resJson = res.bodyAsJsonObject(); JsonObject resJson = res.bodyAsJsonObject();
if ("success".equals(resJson.getString("message")) && resJson.containsKey("data")) { if ("success".equals(resJson.getString("message")) && resJson.containsKey("data")) {
JsonObject dataJson = resJson.getJsonObject("data"); JsonObject dataJson = resJson.getJsonObject("data");
@@ -44,19 +42,15 @@ public class CowTool implements IPanTool {
promise.complete(downloadUrl); promise.complete(downloadUrl);
return; return;
} }
fail("cow parse fail: {}; downloadUrl is empty", url2);
log.error("cow parse fail: {}; downloadUrl is empty", url2);
promise.fail("cow parse fail: " + url2 + "; downloadUrl is empty");
return; return;
} }
log.error("cow parse fail: {}; json: {}", url2, res2Json); fail("cow parse fail: {}; json: {}", url2, res2Json);
promise.fail("cow parse fail: " + url2 + "; json:" + res2Json); }).onFailure(handleFail(url2));
});
return; return;
} }
log.error("cow parse fail: {}; json: {}", key, resJson); fail("cow parse fail: {}; json: {}", key, resJson);
promise.fail("cow parse fail: " + key + "; json:" + resJson); }).onFailure(handleFail(url));
}).onFailure(t -> promise.fail(PanExceptionUtils.fillRunTimeException("Cow", key, t)));
return promise.future(); return promise.future();
} }

View File

@@ -1,22 +1,17 @@
package cn.qaiu.lz.common.parser.impl; package cn.qaiu.lz.common.parser.impl;
import cn.qaiu.lz.common.parser.IPanTool; import cn.qaiu.lz.common.parser.IPanTool;
import cn.qaiu.lz.common.parser.PanBase;
import cn.qaiu.lz.common.util.CommonUtils; import cn.qaiu.lz.common.util.CommonUtils;
import cn.qaiu.lz.common.util.PanExceptionUtils;
import cn.qaiu.vx.core.util.VertxHolder;
import io.vertx.core.Future; import io.vertx.core.Future;
import io.vertx.core.Promise;
import io.vertx.core.json.JsonArray; import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject; import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.client.WebClient;
import io.vertx.uritemplate.UriTemplate; import io.vertx.uritemplate.UriTemplate;
import lombok.extern.slf4j.Slf4j;
/** /**
* 移动云空间解析 * 移动云空间解析
*/ */
@Slf4j public class EcTool extends PanBase implements IPanTool {
public class EcTool implements IPanTool {
private static final String FIRST_REQUEST_URL = "https://www.ecpan.cn/drive/fileextoverrid" + private static final String FIRST_REQUEST_URL = "https://www.ecpan.cn/drive/fileextoverrid" +
".do?chainUrlTemplate=https:%2F%2Fwww.ecpan" + ".do?chainUrlTemplate=https:%2F%2Fwww.ecpan" +
".cn%2Fweb%2F%23%2FyunpanProxy%3Fpath%3D%252F%2523%252Fdrive%252Foutside&parentId=-1&data={dataKey}"; ".cn%2Fweb%2F%23%2FyunpanProxy%3Fpath%3D%252F%2523%252Fdrive%252Foutside&parentId=-1&data={dataKey}";
@@ -25,10 +20,12 @@ public class EcTool implements IPanTool {
public static final String SHARE_URL_PREFIX = "www.ecpan.cn/"; public static final String SHARE_URL_PREFIX = "www.ecpan.cn/";
public Future<String> parse(String data, String code) { public EcTool(String key, String pwd) {
String dataKey = CommonUtils.adaptShortPaths(SHARE_URL_PREFIX, data); super(key, pwd);
Promise<String> promise = Promise.promise(); }
WebClient client = WebClient.create(VertxHolder.getVertxInstance());
public Future<String> parse() {
String dataKey = CommonUtils.adaptShortPaths(SHARE_URL_PREFIX, key);
// 第一次请求 获取文件信息 // 第一次请求 获取文件信息
client.getAbs(UriTemplate.of(FIRST_REQUEST_URL)).setTemplateParam("dataKey", dataKey).send().onSuccess(res -> { client.getAbs(UriTemplate.of(FIRST_REQUEST_URL)).setTemplateParam("dataKey", dataKey).send().onSuccess(res -> {
JsonObject jsonObject = res.bodyAsJsonObject(); JsonObject jsonObject = res.bodyAsJsonObject();
@@ -37,8 +34,7 @@ public class EcTool implements IPanTool {
.getJsonObject("var") .getJsonObject("var")
.getJsonObject("chainFileInfo"); .getJsonObject("chainFileInfo");
if (fileInfo.containsKey("errMesg")) { if (fileInfo.containsKey("errMesg")) {
promise.fail(new RuntimeException(DOWNLOAD_REQUEST_URL + " 解析失败: " fail("{} 解析失败:{} key = {}", FIRST_REQUEST_URL, fileInfo.getString("errMesg"), dataKey);
+ fileInfo.getString("errMesg")) + " key = " + dataKey);
return; return;
} }
JsonObject cloudpFile = fileInfo.getJsonObject("cloudpFile"); JsonObject cloudpFile = fileInfo.getJsonObject("cloudpFile");
@@ -55,9 +51,9 @@ public class EcTool implements IPanTool {
JsonObject jsonRes = res2.bodyAsJsonObject(); JsonObject jsonRes = res2.bodyAsJsonObject();
log.debug("ecPan get download url -> {}", res2.body().toString()); log.debug("ecPan get download url -> {}", res2.body().toString());
promise.complete(jsonRes.getJsonObject("var").getString("downloadUrl")); promise.complete(jsonRes.getJsonObject("var").getString("downloadUrl"));
}).onFailure(t -> promise.fail(PanExceptionUtils.fillRunTimeException("Ec", dataKey, t))); }).onFailure(handleFail(""));
} }
).onFailure(t -> promise.fail(PanExceptionUtils.fillRunTimeException("Ec", dataKey, t)));; ).onFailure(handleFail(FIRST_REQUEST_URL));
return promise.future(); return promise.future();
} }
} }

View File

@@ -1,18 +1,14 @@
package cn.qaiu.lz.common.parser.impl; package cn.qaiu.lz.common.parser.impl;
import cn.qaiu.lz.common.parser.IPanTool; import cn.qaiu.lz.common.parser.IPanTool;
import cn.qaiu.lz.common.parser.PanBase;
import cn.qaiu.lz.common.util.CommonUtils; import cn.qaiu.lz.common.util.CommonUtils;
import cn.qaiu.lz.common.util.PanExceptionUtils;
import cn.qaiu.vx.core.util.VertxHolder;
import io.vertx.core.Future; import io.vertx.core.Future;
import io.vertx.core.MultiMap; import io.vertx.core.MultiMap;
import io.vertx.core.Promise; import io.vertx.core.Promise;
import io.vertx.core.Vertx;
import io.vertx.core.buffer.Buffer; import io.vertx.core.buffer.Buffer;
import io.vertx.core.json.JsonObject; import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.client.HttpResponse; import io.vertx.ext.web.client.HttpResponse;
import io.vertx.ext.web.client.WebClient;
import io.vertx.ext.web.client.WebClientOptions;
import io.vertx.ext.web.client.WebClientSession; import io.vertx.ext.web.client.WebClientSession;
import io.vertx.uritemplate.UriTemplate; import io.vertx.uritemplate.UriTemplate;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@@ -23,7 +19,7 @@ import java.util.regex.Pattern;
/** /**
* 360亿方云 * 360亿方云
*/ */
public class FcTool implements IPanTool { public class FcTool extends PanBase implements IPanTool {
public static final String SHARE_URL_PREFIX0 = "https://v2.fangcloud.com/s"; public static final String SHARE_URL_PREFIX0 = "https://v2.fangcloud.com/s";
public static final String SHARE_URL_PREFIX = "https://v2.fangcloud.com/sharing/"; public static final String SHARE_URL_PREFIX = "https://v2.fangcloud.com/sharing/";
@@ -31,45 +27,44 @@ public class FcTool implements IPanTool {
private static final String DOWN_REQUEST_URL = "https://v2.fangcloud.cn/apps/files/download?file_id={fid}" + private static final String DOWN_REQUEST_URL = "https://v2.fangcloud.cn/apps/files/download?file_id={fid}" +
"&scenario=share&unique_name={uname}"; "&scenario=share&unique_name={uname}";
public Future<String> parse(String data, String code) { public FcTool(String key, String pwd) {
data = data.replace("share","sharing"); super(key, pwd);
}
public Future<String> parse() {
String data = key.replace("share","sharing");
String dataKey = CommonUtils.adaptShortPaths(SHARE_URL_PREFIX, data); String dataKey = CommonUtils.adaptShortPaths(SHARE_URL_PREFIX, data);
Promise<String> promise = Promise.promise();
Vertx vertx = VertxHolder.getVertxInstance();
WebClient client = WebClient.create(vertx);
WebClientSession sClient = WebClientSession.create(client); WebClientSession sClient = WebClientSession.create(client);
// 第一次请求 自动重定向 // 第一次请求 自动重定向
sClient.getAbs(SHARE_URL_PREFIX + dataKey).send().onSuccess(res -> { sClient.getAbs(SHARE_URL_PREFIX + dataKey).send().onSuccess(res -> {
// 判断是否是加密分享 // 判断是否是加密分享
if (StringUtils.isNotEmpty(code)) { if (StringUtils.isNotEmpty(pwd)) {
// 获取requesttoken // 获取requesttoken
String html = res.bodyAsString(); String html = res.bodyAsString();
Pattern compile = Pattern.compile("name=\"requesttoken\"\\s+value=\"([a-zA-Z0-9_+=]+)\""); Pattern compile = Pattern.compile("name=\"requesttoken\"\\s+value=\"([a-zA-Z0-9_+=]+)\"");
Matcher matcher = compile.matcher(html); Matcher matcher = compile.matcher(html);
if (!matcher.find()) { if (!matcher.find()) {
promise.fail(SHARE_URL_PREFIX + " 未匹配到加密分享的密码输入页面的requesttoken: \n" + html); fail(SHARE_URL_PREFIX + " 未匹配到加密分享的密码输入页面的requesttoken");
return; return;
} }
String token = matcher.group(1); String token = matcher.group(1);
sClient.postAbs(SHARE_URL_PREFIX2 + dataKey).sendForm(MultiMap.caseInsensitiveMultiMap() sClient.postAbs(SHARE_URL_PREFIX2 + dataKey).sendForm(MultiMap.caseInsensitiveMultiMap()
.set("requesttoken", token) .set("requesttoken", token)
.set("password", code)).onSuccess(res2 -> { .set("password", pwd)).onSuccess(res2 -> {
if (res2.statusCode() == 302) { if (res2.statusCode() == 302) {
sClient.getAbs(res2.getHeader("Location")).send().onSuccess(res3 -> sClient.getAbs(res2.getHeader("Location")).send()
getDownURL(dataKey, promise, res3, sClient)) .onSuccess(res3 -> getDownURL(dataKey, promise, res3, sClient))
.onFailure(t -> promise.fail(PanExceptionUtils.fillRunTimeException("Fc", dataKey, t))); .onFailure(handleFail(res2.getHeader("Location")));
return; return;
} }
promise.fail(SHARE_URL_PREFIX + " 密码跳转后获取重定向失败 \n" + html); fail(SHARE_URL_PREFIX + " 密码跳转后获取重定向失败");
}).onFailure(t -> promise.fail(PanExceptionUtils.fillRunTimeException("Fc", dataKey, t))); }).onFailure(handleFail(SHARE_URL_PREFIX2));
return; return;
} }
getDownURL(dataKey, promise, res, sClient); getDownURL(dataKey, promise, res, sClient);
}).onFailure(t -> promise.fail(PanExceptionUtils.fillRunTimeException("Fc", dataKey, t))); }).onFailure(handleFail(SHARE_URL_PREFIX + dataKey));
return promise.future(); return promise.future();
} }
@@ -80,14 +75,12 @@ public class FcTool implements IPanTool {
Pattern compile = Pattern.compile("id=\"typed_id\"\\s+value=\"file_(\\d+)\""); Pattern compile = Pattern.compile("id=\"typed_id\"\\s+value=\"file_(\\d+)\"");
Matcher matcher = compile.matcher(html); Matcher matcher = compile.matcher(html);
if (!matcher.find()) { if (!matcher.find()) {
promise.fail(SHARE_URL_PREFIX + " 未匹配到文件id(typed_id): \n" + html); fail(SHARE_URL_PREFIX + " 未匹配到文件id(typed_id)");
return; return;
} }
String fid = matcher.group(1); String fid = matcher.group(1);
// 创建一个不自动重定向的WebClientSession // 创建一个不自动重定向的WebClientSession
WebClient clientNoRedirects = WebClient.create(VertxHolder.getVertxInstance(),
new WebClientOptions().setFollowRedirects(false));
WebClientSession sClientNoRedirects = WebClientSession.create(clientNoRedirects, sClient.cookieStore()); WebClientSession sClientNoRedirects = WebClientSession.create(clientNoRedirects, sClient.cookieStore());
// 第二次请求 // 第二次请求
sClientNoRedirects.getAbs(UriTemplate.of(DOWN_REQUEST_URL)) sClientNoRedirects.getAbs(UriTemplate.of(DOWN_REQUEST_URL))
@@ -97,14 +90,14 @@ public class FcTool implements IPanTool {
try { try {
resJson = res2.bodyAsJsonObject(); resJson = res2.bodyAsJsonObject();
} catch (Exception e) { } catch (Exception e) {
promise.fail(DOWN_REQUEST_URL + " 第二次请求没有返回JSON, 可能下载受限: " + res2.bodyAsString()); fail(e, DOWN_REQUEST_URL + " 第二次请求没有返回JSON, 可能下载受限");
return; return;
} }
if (!resJson.getBoolean("success")) { if (!resJson.getBoolean("success")) {
promise.fail(DOWN_REQUEST_URL + " 第二次请求未得到正确相应: " + resJson); fail(DOWN_REQUEST_URL + " 第二次请求未得到正确相应: " + resJson);
return; return;
} }
promise.complete(resJson.getString("download_url")); promise.complete(resJson.getString("download_url"));
}).onFailure(t -> promise.fail(PanExceptionUtils.fillRunTimeException("Fc", dataKey, t))); }).onFailure(handleFail(DOWN_REQUEST_URL));
} }
} }

View File

@@ -1,13 +1,12 @@
package cn.qaiu.lz.common.parser.impl; package cn.qaiu.lz.common.parser.impl;
import cn.qaiu.lz.common.parser.IPanTool; import cn.qaiu.lz.common.parser.IPanTool;
import cn.qaiu.lz.common.parser.PanBase;
import cn.qaiu.lz.common.util.AESUtils; import cn.qaiu.lz.common.util.AESUtils;
import cn.qaiu.lz.common.util.CommonUtils; import cn.qaiu.lz.common.util.CommonUtils;
import cn.qaiu.lz.common.util.PanExceptionUtils;
import cn.qaiu.vx.core.util.VertxHolder; import cn.qaiu.vx.core.util.VertxHolder;
import io.vertx.core.Future; import io.vertx.core.Future;
import io.vertx.core.MultiMap; import io.vertx.core.MultiMap;
import io.vertx.core.Promise;
import io.vertx.core.json.JsonObject; import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.client.WebClient; import io.vertx.ext.web.client.WebClient;
import io.vertx.ext.web.client.WebClientOptions; import io.vertx.ext.web.client.WebClientOptions;
@@ -20,7 +19,7 @@ import java.util.UUID;
* *
* @version V016_230609 * @version V016_230609
*/ */
public class FjTool implements IPanTool { public class FjTool extends PanBase implements IPanTool {
public static final String SHARE_URL_PREFIX = "https://www.feijix.com/s/"; public static final String SHARE_URL_PREFIX = "https://www.feijix.com/s/";
private static final String API_URL_PREFIX = "https://api.feijipan.com/ws/"; private static final String API_URL_PREFIX = "https://api.feijipan.com/ws/";
@@ -31,10 +30,13 @@ public class FjTool implements IPanTool {
private static final String SECOND_REQUEST_URL = API_URL_PREFIX + "file/redirect?downloadId={fidEncode}&enable=1" + private static final String SECOND_REQUEST_URL = API_URL_PREFIX + "file/redirect?downloadId={fidEncode}&enable=1" +
"&devType=6&uuid={uuid}&timestamp={ts}&auth={auth}"; "&devType=6&uuid={uuid}&timestamp={ts}&auth={auth}";
public Future<String> parse(String data, String code) { public FjTool(String key, String pwd) {
String dataKey = CommonUtils.adaptShortPaths(SHARE_URL_PREFIX, data); super(key, pwd);
}
public Future<String> parse() {
String dataKey = CommonUtils.adaptShortPaths(SHARE_URL_PREFIX, key);
Promise<String> promise = Promise.promise();
WebClient client = WebClient.create(VertxHolder.getVertxInstance(), WebClient client = WebClient.create(VertxHolder.getVertxInstance(),
new WebClientOptions().setFollowRedirects(false)); new WebClientOptions().setFollowRedirects(false));
String shareId = String.valueOf(AESUtils.idEncrypt(dataKey)); String shareId = String.valueOf(AESUtils.idEncrypt(dataKey));
@@ -44,11 +46,11 @@ public class FjTool implements IPanTool {
client.postAbs(UriTemplate.of(FIRST_REQUEST_URL)).setTemplateParam("shareId", shareId).send().onSuccess(res -> { client.postAbs(UriTemplate.of(FIRST_REQUEST_URL)).setTemplateParam("shareId", shareId).send().onSuccess(res -> {
JsonObject resJson = res.bodyAsJsonObject(); JsonObject resJson = res.bodyAsJsonObject();
if (resJson.getInteger("code") != 200) { if (resJson.getInteger("code") != 200) {
promise.fail(FIRST_REQUEST_URL + " 返回异常: " + resJson); fail(FIRST_REQUEST_URL + " 返回异常: " + resJson);
return; return;
} }
if (resJson.getJsonArray("list").size() == 0) { if (resJson.getJsonArray("list").size() == 0) {
promise.fail(FIRST_REQUEST_URL + " 解析文件列表为空: " + resJson); fail(FIRST_REQUEST_URL + " 解析文件列表为空: " + resJson);
return; return;
} }
// 文件Id // 文件Id
@@ -67,12 +69,12 @@ public class FjTool implements IPanTool {
.setTemplateParam("auth", auth).send().onSuccess(res2 -> { .setTemplateParam("auth", auth).send().onSuccess(res2 -> {
MultiMap headers = res2.headers(); MultiMap headers = res2.headers();
if (!headers.contains("Location")) { if (!headers.contains("Location")) {
promise.fail(SECOND_REQUEST_URL + " 未找到重定向URL: \n" + res.headers()); fail(SECOND_REQUEST_URL + " 未找到重定向URL: \n" + res.headers());
return; return;
} }
promise.complete(headers.get("Location")); promise.complete(headers.get("Location"));
}).onFailure(t -> promise.fail(PanExceptionUtils.fillRunTimeException("Fj", dataKey, t))); }).onFailure(handleFail(SECOND_REQUEST_URL));
}).onFailure(t -> promise.fail(PanExceptionUtils.fillRunTimeException("Fj", dataKey, t))); }).onFailure(handleFail(FIRST_REQUEST_URL));
return promise.future(); return promise.future();
} }

View File

@@ -1,7 +1,7 @@
package cn.qaiu.lz.common.parser.impl; package cn.qaiu.lz.common.parser.impl;
import cn.qaiu.lz.common.parser.IPanTool; import cn.qaiu.lz.common.parser.IPanTool;
import cn.qaiu.lz.common.util.PanExceptionUtils; import cn.qaiu.lz.common.parser.PanBase;
import cn.qaiu.vx.core.util.VertxHolder; import cn.qaiu.vx.core.util.VertxHolder;
import io.vertx.core.Future; import io.vertx.core.Future;
import io.vertx.core.MultiMap; import io.vertx.core.MultiMap;
@@ -19,17 +19,20 @@ import java.util.regex.Pattern;
* @author QAIU * @author QAIU
* @version 1.0 update 2021/5/16 10:39 * @version 1.0 update 2021/5/16 10:39
*/ */
public class LzTool implements IPanTool { public class LzTool extends PanBase implements IPanTool {
public static final String SHARE_URL_PREFIX = "https://wwwa.lanzoui.com"; public static final String SHARE_URL_PREFIX = "https://wwwa.lanzoui.com";
public Future<String> parse(String data, String code) { public LzTool(String key, String pwd) {
Promise<String> promise = Promise.promise(); super(key, pwd);
String key = data.indexOf('/') > 0 ? data : SHARE_URL_PREFIX + "/" + data; }
public Future<String> parse() {
String sUrl = key.startsWith("https://") ? key : SHARE_URL_PREFIX + "/" + key;
WebClient client = WebClient.create(VertxHolder.getVertxInstance(), WebClient client = WebClient.create(VertxHolder.getVertxInstance(),
new WebClientOptions().setFollowRedirects(false)); new WebClientOptions().setFollowRedirects(false));
client.getAbs(key).send().onSuccess(res -> { client.getAbs(sUrl).send().onSuccess(res -> {
String html = res.bodyAsString(); String html = res.bodyAsString();
// 匹配iframe // 匹配iframe
Pattern compile = Pattern.compile("src=\"(/fn\\?[a-zA-Z\\d_+/=]{16,})\""); Pattern compile = Pattern.compile("src=\"(/fn\\?[a-zA-Z\\d_+/=]{16,})\"");
@@ -39,11 +42,11 @@ public class LzTool implements IPanTool {
Pattern compile2 = Pattern.compile("sign=(\\w{16,})"); Pattern compile2 = Pattern.compile("sign=(\\w{16,})");
Matcher matcher2 = compile2.matcher(html); Matcher matcher2 = compile2.matcher(html);
if (!matcher2.find()) { if (!matcher2.find()) {
promise.fail(key + ": sign正则匹配失败, 可能分享已失效: " + html); fail(sUrl + ": sign正则匹配失败, 可能分享已失效");
return; return;
} }
String sign = matcher2.group(1); String sign = matcher2.group(1);
getDownURL(promise, code, key, client, sign); getDownURL(promise, sUrl, client, sign);
return; return;
} }
String iframePath = matcher.group(1); String iframePath = matcher.group(1);
@@ -52,17 +55,17 @@ public class LzTool implements IPanTool {
System.out.println(html); System.out.println(html);
Matcher matcher2 = Pattern.compile("'sign'\s*:\s*'(\\w+)'").matcher(html2); Matcher matcher2 = Pattern.compile("'sign'\s*:\s*'(\\w+)'").matcher(html2);
if (!matcher2.find()) { if (!matcher2.find()) {
promise.fail(SHARE_URL_PREFIX + iframePath + " -> " + key + ": sign正则匹配失败, 可能分享已失效: " + html2); fail(SHARE_URL_PREFIX + iframePath + " -> " + sUrl + ": sign正则匹配失败, 可能分享已失效");
return; return;
} }
String sign = matcher2.group(1); String sign = matcher2.group(1);
getDownURL(promise, code, key, client, sign); getDownURL(promise, sUrl, client, sign);
}).onFailure(t -> promise.fail(PanExceptionUtils.fillRunTimeException("Lz", key, t))); }).onFailure(handleFail(SHARE_URL_PREFIX));
}).onFailure(t -> promise.fail(PanExceptionUtils.fillRunTimeException("Lz", key, t))); }).onFailure(handleFail(sUrl));
return promise.future(); return promise.future();
} }
private void getDownURL(Promise<String> promise, String code, String key, WebClient client, String sign) { private void getDownURL(Promise<String> promise, String key, WebClient client, String sign) {
MultiMap headers = MultiMap.caseInsensitiveMultiMap(); MultiMap headers = MultiMap.caseInsensitiveMultiMap();
var userAgent2 = "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, " + var userAgent2 = "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, " +
"like " + "like " +
@@ -73,19 +76,20 @@ public class LzTool implements IPanTool {
headers.set("Accept-Language", "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2"); headers.set("Accept-Language", "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2");
headers.set("sec-ch-ua-mobile", "sec-ch-ua-mobile"); headers.set("sec-ch-ua-mobile", "sec-ch-ua-mobile");
client.postAbs(SHARE_URL_PREFIX + "/ajaxm.php").putHeaders(headers).sendForm(MultiMap String url = SHARE_URL_PREFIX + "/ajaxm.php";
client.postAbs(url).putHeaders(headers).sendForm(MultiMap
.caseInsensitiveMultiMap() .caseInsensitiveMultiMap()
.set("action", "downprocess") .set("action", "downprocess")
.set("sign", sign).set("p", code)).onSuccess(res2 -> { .set("sign", sign).set("p", pwd)).onSuccess(res2 -> {
JsonObject urlJson = res2.bodyAsJsonObject(); JsonObject urlJson = res2.bodyAsJsonObject();
if (urlJson.getInteger("zt") != 1) { if (urlJson.getInteger("zt") != 1) {
promise.fail(urlJson.getString("inf")); fail(urlJson.getString("inf"));
return; return;
} }
String downUrl = urlJson.getString("dom") + "/file/" + urlJson.getString("url"); String downUrl = urlJson.getString("dom") + "/file/" + urlJson.getString("url");
client.getAbs(downUrl).putHeaders(headers).send() client.getAbs(downUrl).putHeaders(headers).send()
.onSuccess(res3 -> promise.complete(res3.headers().get("Location"))) .onSuccess(res3 -> promise.complete(res3.headers().get("Location")))
.onFailure(t -> promise.fail(PanExceptionUtils.fillRunTimeException("Lz", key, t))); .onFailure(handleFail(downUrl));
}).onFailure(t -> promise.fail(PanExceptionUtils.fillRunTimeException("Lz", key, t))); }).onFailure(handleFail(url));
} }
} }

View File

@@ -4,7 +4,7 @@ import io.vertx.core.Future;
import io.vertx.core.Promise; import io.vertx.core.Promise;
public class QkTool { public class QkTool {
public static Future<String> parse(String data, String code) { public static Future<String> parse() {
Promise<String> promise = Promise.promise(); Promise<String> promise = Promise.promise();
return promise.future(); return promise.future();

View File

@@ -1,22 +1,17 @@
package cn.qaiu.lz.common.parser.impl; package cn.qaiu.lz.common.parser.impl;
import cn.qaiu.lz.common.parser.IPanTool; import cn.qaiu.lz.common.parser.IPanTool;
import cn.qaiu.lz.common.parser.PanBase;
import cn.qaiu.lz.common.util.CommonUtils; import cn.qaiu.lz.common.util.CommonUtils;
import cn.qaiu.lz.common.util.PanExceptionUtils;
import cn.qaiu.vx.core.util.VertxHolder;
import io.vertx.core.Future; import io.vertx.core.Future;
import io.vertx.core.Promise;
import io.vertx.core.json.JsonArray; import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject; import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.client.WebClient;
import io.vertx.uritemplate.UriTemplate; import io.vertx.uritemplate.UriTemplate;
import lombok.extern.slf4j.Slf4j;
/** /**
* UC网盘解析 * UC网盘解析
*/ */
@Slf4j public class UcTool extends PanBase implements IPanTool {
public class UcTool implements IPanTool {
private static final String API_URL_PREFIX = "https://pc-api.uc.cn/1/clouddrive/"; private static final String API_URL_PREFIX = "https://pc-api.uc.cn/1/clouddrive/";
public static final String SHARE_URL_PREFIX = "https://fast.uc.cn/s/"; public static final String SHARE_URL_PREFIX = "https://fast.uc.cn/s/";
@@ -29,11 +24,13 @@ public class UcTool implements IPanTool {
private static final String THIRD_REQUEST_URL = API_URL_PREFIX + "file/download?entry=ft&fr=pc&pr=UCBrowser"; private static final String THIRD_REQUEST_URL = API_URL_PREFIX + "file/download?entry=ft&fr=pc&pr=UCBrowser";
public Future<String> parse(String data, String code) { public UcTool(String key, String pwd) {
var dataKey = CommonUtils.adaptShortPaths(SHARE_URL_PREFIX, data); super(key, pwd);
var passcode = (code == null) ? "" : code; }
Promise<String> promise = Promise.promise();
var client = WebClient.create(VertxHolder.getVertxInstance()); public Future<String> parse() {
var dataKey = CommonUtils.adaptShortPaths(SHARE_URL_PREFIX, key);
var passcode = (pwd == null) ? "" : pwd;
var jsonObject = JsonObject.of("share_for_transfer", true); var jsonObject = JsonObject.of("share_for_transfer", true);
jsonObject.put("pwd_id", dataKey); jsonObject.put("pwd_id", dataKey);
jsonObject.put("passcode", passcode); jsonObject.put("passcode", passcode);
@@ -42,7 +39,7 @@ public class UcTool implements IPanTool {
log.debug("第一阶段 {}", res.body()); log.debug("第一阶段 {}", res.body());
var resJson = res.bodyAsJsonObject(); var resJson = res.bodyAsJsonObject();
if (resJson.getInteger("code") != 0) { if (resJson.getInteger("code") != 0) {
promise.fail(FIRST_REQUEST_URL + " 返回异常: " + resJson); fail(FIRST_REQUEST_URL + " 返回异常: " + resJson);
return; return;
} }
var stoken = resJson.getJsonObject("data").getString("stoken"); var stoken = resJson.getJsonObject("data").getString("stoken");
@@ -55,7 +52,7 @@ public class UcTool implements IPanTool {
log.debug("第二阶段 {}", res2.body()); log.debug("第二阶段 {}", res2.body());
JsonObject resJson2 = res2.bodyAsJsonObject(); JsonObject resJson2 = res2.bodyAsJsonObject();
if (resJson2.getInteger("code") != 0) { if (resJson2.getInteger("code") != 0) {
promise.fail(FIRST_REQUEST_URL + " 返回异常: " + resJson2); fail(FIRST_REQUEST_URL + " 返回异常: " + resJson2);
return; return;
} }
// 文件信息 // 文件信息
@@ -71,15 +68,15 @@ public class UcTool implements IPanTool {
log.debug("第三阶段 {}", res3.body()); log.debug("第三阶段 {}", res3.body());
var resJson3 = res3.bodyAsJsonObject(); var resJson3 = res3.bodyAsJsonObject();
if (resJson3.getInteger("code") != 0) { if (resJson3.getInteger("code") != 0) {
promise.fail(FIRST_REQUEST_URL + " 返回异常: " + resJson2); fail(FIRST_REQUEST_URL + " 返回异常: " + resJson2);
return; return;
} }
promise.complete(resJson3.getJsonArray("data").getJsonObject(0).getString("download_url")); promise.complete(resJson3.getJsonArray("data").getJsonObject(0).getString("download_url"));
}).onFailure(t -> promise.fail(PanExceptionUtils.fillRunTimeException("Uc", dataKey, t))); }).onFailure(handleFail(THIRD_REQUEST_URL));
}).onFailure(t -> promise.fail(new RuntimeException("解析异常: ", t.fillInStackTrace()))); }).onFailure(handleFail(SECOND_REQUEST_URL));
} }
).onFailure(t -> promise.fail(PanExceptionUtils.fillRunTimeException("Uc", dataKey, t))); ).onFailure(handleFail(FIRST_REQUEST_URL));
return promise.future(); return promise.future();
} }
} }

View File

@@ -4,8 +4,6 @@ import cn.qaiu.lz.common.parser.IPanTool;
import cn.qaiu.lz.common.parser.PanBase; import cn.qaiu.lz.common.parser.PanBase;
import cn.qaiu.lz.common.util.CommonUtils; import cn.qaiu.lz.common.util.CommonUtils;
import cn.qaiu.lz.common.util.JsExecUtils; import cn.qaiu.lz.common.util.JsExecUtils;
import cn.qaiu.lz.common.util.PanExceptionUtils;
import cn.qaiu.vx.core.util.VertxHolder;
import io.vertx.core.Future; import io.vertx.core.Future;
import io.vertx.core.json.JsonObject; import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.client.WebClient; import io.vertx.ext.web.client.WebClient;
@@ -26,15 +24,6 @@ public class YeTool extends PanBase implements IPanTool {
public static final String SHARE_URL_PREFIX = "https://www.123pan.com/s/"; public static final String SHARE_URL_PREFIX = "https://www.123pan.com/s/";
public static final String FIRST_REQUEST_URL = SHARE_URL_PREFIX + "{key}.html"; public static final String FIRST_REQUEST_URL = SHARE_URL_PREFIX + "{key}.html";
/*
private static final String GET_FILE_INFO_URL = "https://www.123pan.com/a/api/share/get?limit=100&next=1&orderBy" +
"=file_name&orderDirection=asc&shareKey={shareKey}&SharePwd={pwd}&ParentFileId=0&Page=1&event" +
"=homeListFile&operateType=1";
private static final String GET_FILE_INFO_URL="https://www.123pan
.com/b/api/share/get?limit=100&next=1&orderBy=file_name&orderDirection=asc" +
"&shareKey={shareKey}&SharePwd={pwd}&ParentFileId=0&Page=1&event=homeListFile&operateType=1&auth-key
={authKey}";
*/
private static final String GET_FILE_INFO_URL = "https://www.123pan.com/b/api/share/get?limit=100&next=1&orderBy" + private static final String GET_FILE_INFO_URL = "https://www.123pan.com/b/api/share/get?limit=100&next=1&orderBy" +
"=file_name&orderDirection=asc" + "=file_name&orderDirection=asc" +
@@ -48,7 +37,6 @@ public class YeTool extends PanBase implements IPanTool {
public Future<String> parse() { public Future<String> parse() {
String dataKey = CommonUtils.adaptShortPaths(SHARE_URL_PREFIX, key); String dataKey = CommonUtils.adaptShortPaths(SHARE_URL_PREFIX, key);
WebClient client = WebClient.create(VertxHolder.getVertxInstance());
client.getAbs(UriTemplate.of(FIRST_REQUEST_URL)).setTemplateParam("key", dataKey).send().onSuccess(res -> { client.getAbs(UriTemplate.of(FIRST_REQUEST_URL)).setTemplateParam("key", dataKey).send().onSuccess(res -> {
@@ -89,9 +77,9 @@ public class YeTool extends PanBase implements IPanTool {
infoJson.getJsonObject("data").getJsonArray("InfoList").getJsonObject(0); infoJson.getJsonObject("data").getJsonArray("InfoList").getJsonObject(0);
getFileInfoJson.put("ShareKey", shareKey); getFileInfoJson.put("ShareKey", shareKey);
getDownUrl(client, getFileInfoJson); getDownUrl(client, getFileInfoJson);
}).onFailure(this.handleFail("获取文件信息失败")); }).onFailure(this.handleFail(GET_FILE_INFO_URL));
} else { } else {
fail(dataKey + " 该分享需要密码"); fail("该分享[{}]需要密码",dataKey);
} }
return; return;
} }
@@ -99,7 +87,7 @@ public class YeTool extends PanBase implements IPanTool {
JsonObject reqBodyJson = resListJson.getJsonObject("data").getJsonArray("InfoList").getJsonObject(0); JsonObject reqBodyJson = resListJson.getJsonObject("data").getJsonArray("InfoList").getJsonObject(0);
reqBodyJson.put("ShareKey", shareKey); reqBodyJson.put("ShareKey", shareKey);
getDownUrl(client, reqBodyJson); getDownUrl(client, reqBodyJson);
}).onFailure(this.handleFail("")); }).onFailure(this.handleFail(FIRST_REQUEST_URL));
return promise.future(); return promise.future();
} }
@@ -169,6 +157,6 @@ public class YeTool extends PanBase implements IPanTool {
} catch (MalformedURLException e) { } catch (MalformedURLException e) {
fail("urlParams解析异常" + e.getMessage()); fail("urlParams解析异常" + e.getMessage());
} }
}).onFailure(this::handleFail); }).onFailure(this.handleFail(DOWNLOAD_API_URL));
} }
} }

View File

@@ -43,7 +43,7 @@ public class ServerApi {
url = EcTool.SHARE_URL_PREFIX + request.getParam("data"); url = EcTool.SHARE_URL_PREFIX + request.getParam("data");
} }
try { try {
IPanTool.shareURLPrefixMatching(url).parse(url, pwd).onSuccess(resUrl -> { IPanTool.shareURLPrefixMatching(url, pwd).parse().onSuccess(resUrl -> {
response.putHeader("location", resUrl).setStatusCode(302).end(); response.putHeader("location", resUrl).setStatusCode(302).end();
promise.complete(); promise.complete();
}).onFailure(t -> promise.fail(t.fillInStackTrace())); }).onFailure(t -> promise.fail(t.fillInStackTrace()));
@@ -59,7 +59,7 @@ public class ServerApi {
// 默认读取Url参数会被截断手动获取一下其他参数 // 默认读取Url参数会被截断手动获取一下其他参数
url = EcTool.SHARE_URL_PREFIX + request.getParam("data"); url = EcTool.SHARE_URL_PREFIX + request.getParam("data");
} }
return IPanTool.shareURLPrefixMatching(url).parse(url, pwd); return IPanTool.shareURLPrefixMatching(url, pwd).parse();
} }
@@ -72,7 +72,7 @@ public class ServerApi {
code = keys[1]; code = keys[1];
} }
IPanTool.typeMatching(type).parse(key, code).onSuccess(resUrl -> response.putHeader("location", resUrl) IPanTool.typeMatching(type, key, code).parse().onSuccess(resUrl -> response.putHeader("location", resUrl)
.setStatusCode(302).end()).onFailure(t -> { .setStatusCode(302).end()).onFailure(t -> {
response.putHeader(CONTENT_TYPE, "text/html;charset=utf-8"); response.putHeader(CONTENT_TYPE, "text/html;charset=utf-8");
response.end(t.getMessage()); response.end(t.getMessage());
@@ -87,6 +87,6 @@ public class ServerApi {
key = keys[0]; key = keys[0];
code = keys[1]; code = keys[1];
} }
return IPanTool.typeMatching(type).parse(key, code); return IPanTool.typeMatching(type, key, code).parse();
} }
} }

View File

@@ -65,10 +65,10 @@ GET http://127.0.0.1:6400/fj/tIfhRqH
### 360亿方云 ### 360亿方云
# @no-redirect # @no-redirect
GET http://127.0.0.1:6400/parser?url=https://v2.fangcloud.com/share/2f238f7714cf61cdc631d23d18 GET http://127.0.0.1:6400/parser?url=https://v2.fangcloud.com/sharing/fb54bdf03c66c04334fe3687a3
### 360亿方云 ### 360亿方云
GET http://127.0.0.1:6400/json/fc/30646fefc8bf936a4766ab8a5e GET http://127.0.0.1:6400/json/fc/fb54bdf03c66c04334fe3687a3
### 360亿方云 ### 360亿方云
# @no-redirect # @no-redirect
@@ -91,7 +91,7 @@ GET http://127.0.0.1:6400/ye/iaKtVv-qOECd
### 123 ### 123
# @no-redirect # @no-redirect
GET http://127.0.0.1:6400/parser?url=https://www.123pan.com/s/iaKtVv-6OECd.html&pwd=DcGeasd 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/login1