diff --git a/core/src/main/java/cn/qaiu/vx/core/util/ConfigConstant.java b/core/src/main/java/cn/qaiu/vx/core/util/ConfigConstant.java index 4b60743..619a9cb 100644 --- a/core/src/main/java/cn/qaiu/vx/core/util/ConfigConstant.java +++ b/core/src/main/java/cn/qaiu/vx/core/util/ConfigConstant.java @@ -7,6 +7,8 @@ public interface ConfigConstant { String LOCAL = "local"; String SERVER = "server"; String CACHE = "cache"; + + String PROXY = "proxy"; String GLOBAL_CONFIG = "globalConfig"; String CUSTOM_CONFIG = "customConfig"; String ASYNC_SERVICE_INSTANCES = "asyncServiceInstances"; diff --git a/parser/src/main/java/cn/qaiu/parser/PanBase.java b/parser/src/main/java/cn/qaiu/parser/PanBase.java index 179f100..6bee7ce 100644 --- a/parser/src/main/java/cn/qaiu/parser/PanBase.java +++ b/parser/src/main/java/cn/qaiu/parser/PanBase.java @@ -6,16 +6,22 @@ import io.vertx.core.Future; import io.vertx.core.Handler; import io.vertx.core.Promise; import io.vertx.core.json.DecodeException; +import io.vertx.core.json.Json; import io.vertx.core.json.JsonObject; +import io.vertx.core.net.ProxyOptions; +import io.vertx.core.net.ProxyType; +import io.vertx.core.net.impl.VertxHandler; 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 org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Arrays; import java.util.Iterator; +import java.util.Map; /** * 解析器抽象类包含promise, HTTP Client, 默认失败方法等; @@ -61,6 +67,29 @@ public abstract class PanBase implements IPanTool { */ public PanBase(ShareLinkInfo shareLinkInfo) { this.shareLinkInfo = shareLinkInfo; + if (shareLinkInfo.getOtherParam().containsKey("proxy")) { + JsonObject proxy = (JsonObject) shareLinkInfo.getOtherParam().get("proxy"); + ProxyOptions proxyOptions = new ProxyOptions() + .setType(ProxyType.valueOf(proxy.getString("type").toUpperCase())) + .setHost(proxy.getString("host")) + .setPort(proxy.getInteger("port")); + if (StringUtils.isNotEmpty(proxy.getString("username"))) { + proxyOptions.setUsername(proxy.getString("username")); + } + if (StringUtils.isNotEmpty(proxy.getString("password"))) { + proxyOptions.setUsername(proxy.getString("password")); + } + this.client = WebClient.create(WebClientVertxInit.get(), + new WebClientOptions() + .setUserAgentEnabled(false) + .setProxyOptions(proxyOptions)); + + this.clientSession = WebClientSession.create(client); + this.clientNoRedirects = WebClient.create(WebClientVertxInit.get(), + new WebClientOptions().setFollowRedirects(false) + .setUserAgentEnabled(false) + .setProxyOptions(proxyOptions)); + } } protected PanBase() { diff --git a/parser/src/main/java/cn/qaiu/parser/PanDomainTemplate.java b/parser/src/main/java/cn/qaiu/parser/PanDomainTemplate.java index 7a3704e..d903190 100644 --- a/parser/src/main/java/cn/qaiu/parser/PanDomainTemplate.java +++ b/parser/src/main/java/cn/qaiu/parser/PanDomainTemplate.java @@ -109,6 +109,11 @@ public enum PanDomainTemplate { compile("https://www\\.icloud\\.com\\.cn/iclouddrive/(?[a-z_A-Z\\d-=]+)(#(.+))?"), "https://www.icloud.com.cn/iclouddrive/{shareKey}", PicTool.class), + // https://www.dropbox.com/scl/fi/cwnbms1yn8u6rcatzyta7/emqx-5.0.26-el7-amd64.tar.gz?rlkey=3uoi4bxz5mv93jmlaws0nlol1&e=8&st=fe0lclc2&dl=0 + PDB("dropbox", + compile("https://www.dropbox.com/scl/fi/(?\\w+)/.+?rlkey=(?\\w+).*"), + "https://www.dropbox.com/scl/fi/{shareKey}/?rlkey={pwd}&dl=0", + PdbTool.class), // =====================音乐类解析 分享链接标志->MxxS (单歌曲/普通音质)========================== // http://163cn.tv/xxx @@ -183,6 +188,8 @@ public enum PanDomainTemplate { public static final String KEY = "KEY"; + public static final String PWD = "PWD"; + // 网盘的显示名称,用于用户界面显示 private final String displayName; diff --git a/parser/src/main/java/cn/qaiu/parser/ParserCreate.java b/parser/src/main/java/cn/qaiu/parser/ParserCreate.java index dfafdd5..f1c747f 100644 --- a/parser/src/main/java/cn/qaiu/parser/ParserCreate.java +++ b/parser/src/main/java/cn/qaiu/parser/ParserCreate.java @@ -6,6 +6,7 @@ import org.apache.commons.lang3.StringUtils; import java.util.regex.Matcher; import static cn.qaiu.parser.PanDomainTemplate.KEY; +import static cn.qaiu.parser.PanDomainTemplate.PWD; /** @@ -38,8 +39,16 @@ public class ParserCreate { Matcher matcher = this.panDomainTemplate.getPattern().matcher(shareUrl); if (matcher.find()) { String shareKey = matcher.group(KEY); + // 返回规范化的标准链接 - String standardUrl = getStandardUrlTemplate().replace("{shareKey}", shareKey); + String standardUrl = getStandardUrlTemplate() + .replace("{shareKey}", shareKey); + + try { + String pwd = matcher.group(PWD); + standardUrl = standardUrl .replace("{pwd}", pwd); + } catch (Exception ignored) {} + shareLinkInfo.setShareUrl(shareUrl); shareLinkInfo.setShareKey(shareKey); if (!(panDomainTemplate.ordinal() >= PanDomainTemplate.CE.ordinal())) { diff --git a/parser/src/main/java/cn/qaiu/parser/impl/PdbTool.java b/parser/src/main/java/cn/qaiu/parser/impl/PdbTool.java new file mode 100644 index 0000000..9edac9d --- /dev/null +++ b/parser/src/main/java/cn/qaiu/parser/impl/PdbTool.java @@ -0,0 +1,95 @@ +package cn.qaiu.parser.impl; + +import cn.qaiu.entity.ShareLinkInfo; +import cn.qaiu.parser.IPanTool; +import cn.qaiu.parser.PanBase; +import cn.qaiu.util.URLUtil; +import io.vertx.core.Future; +import io.vertx.core.MultiMap; +import io.vertx.core.buffer.Buffer; +import io.vertx.core.net.ProxyOptions; +import io.vertx.ext.web.client.HttpRequest; +import io.vertx.ext.web.client.HttpResponse; + +import java.net.URL; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +/** + * dropbox + * Dropbox网盘--不支持大陆地区 + */ +public class PdbTool extends PanBase implements IPanTool { + + private static final String API_URL = + "https://www.dropbox.com/sharing/fetch_user_content_link"; + static final String COOKIE_KEY = "__Host-js_csrf="; + + public PdbTool(ShareLinkInfo shareLinkInfo) { + super(shareLinkInfo); + } + + @Override + public Future parse() { + // https://www.dropbox.com/scl/fi/cwnbms1yn8u6rcatzyta7/emqx-5.0.26-el7-amd64.tar.gz?rlkey=3uoi4bxz5mv93jmlaws0nlol1&e=8&st=fe0lclc2&dl=0 + // https://www.dropbox.com/scl/fi/()/Get-Started-with-Dropbox.pdf?rlkey=yrddd6s9gxsq967pmbgtzvfl3&st=2trcc1f3&dl=0 + // + clientSession.getAbs(shareLinkInfo.getShareUrl()) + .send() + .onSuccess(res->{ + List collect = + res.cookies().stream().filter(key -> key.contains(COOKIE_KEY)).toList(); + if (collect.isEmpty()) { + fail("cookie未找到"); + return; + } + Matcher matcher = Pattern.compile(COOKIE_KEY + "([\\w-]+);").matcher(collect.get(0)); + String _t; + if (matcher.find()) { + _t = matcher.group(1); + } else { + fail("cookie未找到"); + return; + } + MultiMap headers = MultiMap.caseInsensitiveMultiMap(); + headers.set("accept", "*/*"); + headers.set("accept-language", "zh-CN,zh;q=0.9"); + headers.set("cache-control", "no-cache"); + headers.set("dnt", "1"); + headers.set("origin", "https://www.dropbox.com"); + headers.set("pragma", "no-cache"); + headers.set("priority", "u=1, i"); + headers.set("referer", shareLinkInfo.getShareUrl()); + headers.set("sec-ch-ua", "\"Chromium\";v=\"130\", \"Microsoft Edge\";v=\"130\", \"Not?A_Brand\";v=\"99\""); + headers.set("sec-ch-ua-mobile", "?0"); + headers.set("sec-ch-ua-platform", "\"Windows\""); + headers.set("sec-fetch-dest", "empty"); + headers.set("sec-fetch-mode", "cors"); + headers.set("sec-fetch-site", "same-origin"); + headers.set("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36 Edg/130.0.0.0"); + headers.set("x-dropbox-client-yaps-attribution", "edison_atlasservlet.file_viewer-edison:prod"); + headers.set("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8"); + try { + URL url = new URL(shareLinkInfo.getShareUrl()); + // https://www.dropbox.com/scl/fi/cwnbms1yn8u6rcatzyta7/xxx?rlkey=xx&dl=0 + String u0 = URLEncoder.encode((url.getProtocol() + "://" + url.getHost() + url.getPath() + "?rlkey=%s&dl=0") + .formatted(URLUtil.from(shareLinkInfo.getShareUrl()).getParam("rlkey")), StandardCharsets.UTF_8); + clientSession.postAbs(API_URL) + .sendBuffer(Buffer.buffer("is_xhr=true&t=%s&url=%s&origin=PREVIEW_PAGE".formatted(_t, u0))) + .onSuccess(res2 -> { + complete(res2.bodyAsString()); + }) + .onFailure(handleFail()); + } catch (Exception e) { + e.printStackTrace(); + } + + }) + .onFailure(handleFail("请求下载链接失败")); + return future(); + } +} diff --git a/parser/src/main/java/cn/qaiu/parser/impl/PgdTool.java b/parser/src/main/java/cn/qaiu/parser/impl/PgdTool.java index f757a8f..1de411d 100644 --- a/parser/src/main/java/cn/qaiu/parser/impl/PgdTool.java +++ b/parser/src/main/java/cn/qaiu/parser/impl/PgdTool.java @@ -31,17 +31,11 @@ public class PgdTool extends PanBase implements IPanTool { public Future parse() { downloadUrl = DOWN_URL_TEMPLATE + "?id=" + shareLinkInfo.getShareKey() + "&export=download"; - if (true) { + if (shareLinkInfo.getOtherParam().containsKey("proxy")) { // if (shareLinkInfo.getOtherParam().containsKey("bypassCheck") // && "true".equalsIgnoreCase(shareLinkInfo.getOtherParam().get("bypassCheck").toString())) { // 发起请求但不真正下载文件, 只检查响应头 - HttpRequest clientAbs = client.headAbs(downloadUrl); - // TODO 判断是否需要代理 - if (true) { - clientAbs.proxy(new ProxyOptions().setHost("127.0.0.1").setPort(7890)); - } - clientAbs - .send() + client.headAbs(downloadUrl).send() .onSuccess(this::handleResponse) .onFailure(handleFail("请求下载链接失败")); return future(); @@ -59,12 +53,7 @@ public class PgdTool extends PanBase implements IPanTool { complete(downloadUrl); } else { // 如果不是文件流类型,从 HTML 中解析出真实下载链接 - HttpRequest clientAbs = client.getAbs(downloadUrl); - // TODO 判断是否需要代理 - if (true) { - clientAbs.proxy(new ProxyOptions().setHost("127.0.0.1").setPort(7890)); - } - clientAbs + client.getAbs(downloadUrl) .send() .onSuccess(res0 -> { parseHtmlForRealLink(res0.bodyAsString()); diff --git a/parser/src/main/java/cn/qaiu/parser/impl/PodTool.java b/parser/src/main/java/cn/qaiu/parser/impl/PodTool.java index a413461..433e445 100644 --- a/parser/src/main/java/cn/qaiu/parser/impl/PodTool.java +++ b/parser/src/main/java/cn/qaiu/parser/impl/PodTool.java @@ -53,6 +53,7 @@ public class PodTool extends PanBase { return promise.future(); } + //https://onedrive.live.com/redir?resid=ABFD0A26E47D3458!4699&e=OggA4s&migratedtospo=true&redeem=aHR0cHM6Ly8xZHJ2Lm1zL3UvcyFBbGcwZmVRbUN2MnJwRnZ1NDQ0aGc1eVZxRGNLP2U9T2dnQTRz // public static void main(String[] args) { // Matcher matcher = redirectUrlRegex.matcher("https://onedrive.live.com/redir?resid=ABFD0A26E47D3458!4698" + // "&authkey=!ACpvXghP5xhG_cg&e=hV98W1"); diff --git a/web-front/package.json b/web-front/package.json index f47fa30..b10f564 100644 --- a/web-front/package.json +++ b/web-front/package.json @@ -9,6 +9,7 @@ }, "dependencies": { "@element-plus/icons-vue": "^2.3.1", + "@vueuse/core": "^11.2.0", "axios": "^1.7.4", "clipboard": "^2.0.11", "core-js": "^3.8.3", @@ -27,8 +28,7 @@ "compression-webpack-plugin": "^11.1.0", "eslint": "^9.14.0", "eslint-plugin-vue": "^9.30.0", - "filemanager-webpack-plugin": "8.0.0", - "typescript": "^5.6.3" + "filemanager-webpack-plugin": "8.0.0" }, "eslintConfig": { "root": true, diff --git a/web-front/src/App.vue b/web-front/src/App.vue index 1fa1389..6f3740f 100644 --- a/web-front/src/App.vue +++ b/web-front/src/App.vue @@ -1,7 +1,10 @@