From adf56cd7683f3b064f3de6e4cdc35cea665dbfe2 Mon Sep 17 00:00:00 2001
From: QAIU <736226400@qq.com>
Date: Fri, 25 Oct 2024 14:38:57 +0800
Subject: [PATCH] =?UTF-8?q?add=20=E9=85=B7=E7=8B=97=E9=9F=B3=E4=B9=90,=20?=
=?UTF-8?q?=E9=85=B7=E6=88=91=E9=9F=B3=E4=B9=90,=20=E7=BD=91=E6=98=93?=
=?UTF-8?q?=E4=BA=91=E9=9F=B3=E4=B9=90,=20QQ=E9=9F=B3=E4=B9=90?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../core/verticle/ReverseProxyVerticle.java | 2 +-
parser/pom.xml | 79 ++++++++++++-
.../src/main/java/cn/qaiu/parser/PanBase.java | 42 ++++++-
.../cn/qaiu/parser/PanDomainTemplate.java | 106 +++++++++++-------
.../src/main/java/cn/qaiu/parser/PanType.java | 13 ---
.../java/cn/qaiu/parser/ParserCreate.java | 24 ++--
.../main/java/cn/qaiu/parser/impl/CeTool.java | 26 ++++-
.../main/java/cn/qaiu/parser/impl/KdTool.java | 26 +++++
.../java/cn/qaiu/parser/impl/MmgTool.java | 3 +-
.../java/cn/qaiu/parser/impl/MnesTool.java | 7 +-
.../impl/{MqqTool.java => MqqsTool.java} | 57 ++++++----
.../java/cn/qaiu/parser/impl/OtherTool.java | 22 ++++
.../src/main/java/cn/qaiu/util/URLUtil.java | 13 ++-
.../src/test/java/cn/qaiu/util/TestRegex.java | 5 +-
.../cn/qaiu/lz/common/util/URLParamUtil.java | 4 -
.../main/resources/http-tools/pan-mne.http | 15 ++-
.../src/main/resources/http-tools/temp.http | 12 ++
.../src/main/resources/http-tools/test.http | 32 +++++-
18 files changed, 376 insertions(+), 112 deletions(-)
delete mode 100644 parser/src/main/java/cn/qaiu/parser/PanType.java
create mode 100644 parser/src/main/java/cn/qaiu/parser/impl/KdTool.java
rename parser/src/main/java/cn/qaiu/parser/impl/{MqqTool.java => MqqsTool.java} (57%)
create mode 100644 parser/src/main/java/cn/qaiu/parser/impl/OtherTool.java
diff --git a/core/src/main/java/cn/qaiu/vx/core/verticle/ReverseProxyVerticle.java b/core/src/main/java/cn/qaiu/vx/core/verticle/ReverseProxyVerticle.java
index c8a6ad0..aa95d3b 100644
--- a/core/src/main/java/cn/qaiu/vx/core/verticle/ReverseProxyVerticle.java
+++ b/core/src/main/java/cn/qaiu/vx/core/verticle/ReverseProxyVerticle.java
@@ -211,7 +211,7 @@ public class ReverseProxyVerticle extends AbstractVerticle {
port = 80;
}
String originPath = url.getPath();
- LOGGER.info("Conf(path, originPath, host, port) ----> {},{},{},{}", path, originPath, host, port);
+ LOGGER.info("path {}, originPath {}, to {}:{}", path, originPath, host, port);
// 注意这里不能origin多个代理地址, 一个实例只能代理一个origin
final HttpProxy httpProxy = HttpProxy.reverseProxy(httpClient);
diff --git a/parser/pom.xml b/parser/pom.xml
index 765f548..bc1fff9 100644
--- a/parser/pom.xml
+++ b/parser/pom.xml
@@ -10,6 +10,11 @@
parser
+ jar
+ ${project.groupId}:${project.artifactId}
+ NFD parser
+ https://qaiu.top
+
UTF-8
@@ -46,10 +51,39 @@
junit
junit
- 4.13.2
+ ${junit.version}
test
+
+
+ MIT License
+ https://opensource.org/license/mit
+
+
+
+
+ qaiu
+ qaiu00@gmail.com
+ https://qaiu.top
+
+
+
+ scm:git@github.com:qaiu/netdisk-fast-download.git
+ scm:git@github.com:qaiu/netdisk-fast-download.git
+ git@github.com:qaiu/netdisk-fast-download.git
+
+
+
+ sonatype
+ https://s01.oss.sonatype.org/content/repositories/snapshots/
+
+
+ sonatype
+ https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/
+
+
+
@@ -62,6 +96,49 @@
${java.version}
+
+ org.apache.maven.plugins
+ maven-source-plugin
+ 3.3.1
+
+ true
+
+
+
+ attach-sources
+
+
+
+
+ org.apache.maven.plugins
+ maven-site-plugin
+ 3.7.1
+
+
+
+ org.apache.maven.plugins
+ maven-gpg-plugin
+ 1.6
+
+
+ sign-artifacts
+ verify
+
+ sign
+
+
+
+
+
+ org.sonatype.central
+ central-publishing-maven-plugin
+ 0.6.0
+ true
+
+ central
+ true
+
+
diff --git a/parser/src/main/java/cn/qaiu/parser/PanBase.java b/parser/src/main/java/cn/qaiu/parser/PanBase.java
index ca74bc5..5addebb 100644
--- a/parser/src/main/java/cn/qaiu/parser/PanBase.java
+++ b/parser/src/main/java/cn/qaiu/parser/PanBase.java
@@ -2,6 +2,7 @@ package cn.qaiu.parser;
import cn.qaiu.WebClientVertxInit;
import cn.qaiu.entity.ShareLinkInfo;
+import io.vertx.core.Future;
import io.vertx.core.Handler;
import io.vertx.core.Promise;
import io.vertx.core.json.DecodeException;
@@ -13,11 +14,14 @@ import io.vertx.ext.web.client.WebClientSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.util.Arrays;
+import java.util.Iterator;
+
/**
* 解析器抽象类包含promise, HTTP Client, 默认失败方法等;
* 新增网盘解析器需要继承该类.
*
实现类命名规则:
- * {网盘标识}Tool, 网盘标识不超过3个字符, 可以取网盘名称首字母缩写或拼音首字母,
+ *
{网盘标识}Tool, 网盘标识不超过5个字符, 可以取网盘名称首字母缩写或拼音首字母,
* 音乐类型的解析以M开头, 例如网易云音乐Mne
*/
public abstract class PanBase implements IPanTool {
@@ -73,11 +77,11 @@ public abstract class PanBase implements IPanTool {
try {
String s = String.format(errorMsg.replaceAll("\\{}", "%s"), args);
log.error("解析异常: " + s, t.fillInStackTrace());
- promise.fail(this.getClass().getSimpleName() + ": 解析异常: " + s + " -> " + t);
+ promise.fail(shareLinkInfo.getPanName() + "-" + shareLinkInfo.getType() + ": 解析异常: " + 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);
+ promise.fail(shareLinkInfo.getPanName() + "-" + shareLinkInfo.getType() + ": 解析异常: " + errorMsg + " -> " + t);
}
}
@@ -91,11 +95,11 @@ public abstract class PanBase implements IPanTool {
try {
String s = String.format(errorMsg.replaceAll("\\{}", "%s"), args);
log.error("解析异常: " + s);
- promise.fail(this.getClass().getSimpleName() + " - 解析异常: " + s);
+ promise.fail(shareLinkInfo.getPanName() + "-" + shareLinkInfo.getType() + " - 解析异常: " + s);
} catch (Exception e) {
log.error("ErrorMsg format fail. The parameter has been discarded", e);
log.error("解析异常: " + errorMsg);
- promise.fail(this.getClass().getSimpleName() + " - 解析异常: " + errorMsg);
+ promise.fail(shareLinkInfo.getPanName() + "-" + shareLinkInfo.getType() + " - 解析异常: " + errorMsg);
}
}
@@ -106,7 +110,7 @@ public abstract class PanBase implements IPanTool {
* @return Handler
*/
protected Handler handleFail(String errorMsg) {
- return t -> fail(this.getClass().getSimpleName() + " - 请求异常 {}: -> {}", errorMsg, t.fillInStackTrace());
+ return t -> fail(shareLinkInfo.getPanName() + "-" + shareLinkInfo.getType() + " - 请求异常 {}: -> {}", errorMsg, t.fillInStackTrace());
}
@@ -128,4 +132,30 @@ public abstract class PanBase implements IPanTool {
promise.complete(url);
}
+ protected Future future() {
+ return promise.future();
+ }
+
+ /**
+ * 调用下一个解析器, 通用域名解析
+ */
+ protected void nextParser() {
+ Iterator iterator = Arrays.asList(PanDomainTemplate.values()).iterator();
+ while (iterator.hasNext()) {
+ if (iterator.next().name().equalsIgnoreCase(shareLinkInfo.getType())) {
+ if (iterator.hasNext()) {
+ PanDomainTemplate next = iterator.next();
+ log.debug("规则不匹配, 处理解析器转发: {} -> {}", shareLinkInfo.getPanName(), next.getDisplayName());
+ ParserCreate.fromType(next.name())
+ .fromAnyShareUrl(shareLinkInfo.getShareUrl())
+ .createTool()
+ .parse()
+ .onComplete(promise);
+ } else {
+ fail("error: 没有下一个解析处理器");
+ }
+ }
+ }
+ }
+
}
diff --git a/parser/src/main/java/cn/qaiu/parser/PanDomainTemplate.java b/parser/src/main/java/cn/qaiu/parser/PanDomainTemplate.java
index f01b01e..eadb24d 100644
--- a/parser/src/main/java/cn/qaiu/parser/PanDomainTemplate.java
+++ b/parser/src/main/java/cn/qaiu/parser/PanDomainTemplate.java
@@ -4,8 +4,11 @@ import cn.qaiu.parser.impl.*;
import java.util.Arrays;
import java.util.Set;
+import java.util.regex.Pattern;
import java.util.stream.Collectors;
+import static java.util.regex.Pattern.compile;
+
/**
* 枚举类 PanDomainTemplate 定义了不同网盘服务的模板信息,包括:
*
@@ -20,126 +23,144 @@ import java.util.stream.Collectors;
*/
public enum PanDomainTemplate {
+
// 网盘定义
LZ("蓝奏云",
- "https://([a-z0-9-]+)?\\.?lanzou[a-z]\\.com/(.+/)?(.+)",
+ compile("https://([a-z0-9-]+)?\\.?lanzou[a-z]\\.com/(.+/)?(?.+)"),
"https://lanzoux.com/{shareKey}",
LzTool.class),
// https://www.feijix.com/s/
// https://share.feijipan.com/s/
FJ("小飞机网盘",
- "https://(share\\.feijipan\\.com|www\\.feijix\\.com)/s/(.+)",
+ compile("https://(share\\.feijipan\\.com|www\\.feijix\\.com)/s/(?.+)"),
"https://www.feijix.com/s/{shareKey}",
FjTool.class),
// https://lecloud.lenovo.com/share/
LE("联想乐云",
- "https://lecloud?\\.lenovo\\.com/share/(.+)",
+ compile("https://lecloud?\\.lenovo\\.com/share/(?.+)"),
"https://lecloud.lenovo.com/share/{shareKey}",
LeTool.class),
// https://v2.fangcloud.com/s/
FC("亿方云",
- "https://v2\\.fangcloud\\.(com|cn)/(s|sharing)/([^/]+)",
+ compile("https://v2\\.fangcloud\\.(com|cn)/(s|sharing)/(?.+)"),
"https://v2.fangcloud.com/s/{shareKey}",
FcTool.class),
// https://www.ilanzou.com/s/
IZ("蓝奏云优享",
- "https://www\\.ilanzou\\.com/s/(.+)",
+ compile("https://www\\.ilanzou\\.com/s/(?.+)"),
"https://www.ilanzou.com/s/{shareKey}",
IzTool.class),
// https://wx.mail.qq.com/ftn/download?
QQ("QQ邮箱中转站",
- "https://i?wx\\.mail\\.qq\\.com/ftn/download\\?(.+)",
+ compile("https://i?wx\\.mail\\.qq\\.com/ftn/download\\?(?.+)"),
"https://iwx.mail.qq.com/ftn/download/{shareKey}",
QQTool.class),
// https://f.ws59.cn/f/或者https://www.wenshushu.cn/f/
WS("文叔叔",
- "https://(f\\.ws([0-9]{2})\\.cn|www\\.wenshushu\\.cn)/f/(.+)",
+ compile("https://(f\\.ws([0-9]{2})\\.cn|www\\.wenshushu\\.cn)/f/(?.+)"),
"https://www.wenshushu.cn/f/{shareKey}",
WsTool.class),
// https://www.123pan.com/s/
YE("123网盘",
- "https://www\\.(123pan|123865|123684)\\.com/s/(.+)",
+ compile("https://www\\.(123pan|123865|123684)\\.com/s/(?.+)(.html)?"),
"https://www.123pan.com/s/{shareKey}",
YeTool.class),
// https://www.ecpan.cn/web/#/yunpanProxy?path=%2F%23%2Fdrive%2Foutside&data={code}&isShare=1
EC("移动云空间",
- "https://www\\.ecpan\\.cn/web(/%23|/#)?/yunpanProxy\\?path=.*&data=" +
- "([^&]+)&isShare=1",
+ compile("https://www\\.ecpan\\.cn/web(/%23|/#)?/yunpanProxy\\?path=.*&data=" +
+ "(?[^&]+)&isShare=1"),
"https://www.ecpan.cn/web/#/yunpanProxy?path=%2F%23%2Fdrive%2Foutside&data={shareKey}&isShare=1",
EcTool.class),
// https://cowtransfer.com/s/
COW("奶牛快传",
- "https://(.*)cowtransfer\\.com/s/(.+)",
+ compile("https://(.*)cowtransfer\\.com/s/(?.+)"),
"https://cowtransfer.com/s/{shareKey}",
CowTool.class),
CT("城通网盘",
- "https://474b\\.com/file/(.+)",
+ compile("https://474b\\.com/file/(?.+)"),
"https://474b.com/file/{shareKey}",
CtTool.class),
// =====================音乐类解析 分享链接标志->MxxS (单歌曲/普通音质)==========================
// http://163cn.tv/xxx
MNES("网易云音乐分享",
- "http(s)?://163cn\\.tv/(.+)",
+ compile("http(s)?://163cn\\.tv/(?.+)"),
"http://163cn.tv/{shareKey}",
MnesTool.class),
- MNE("网易云音乐",
- "https://music\\.163\\.com/(#/)?song\\?id=(.+)",
+ // https://music.163.com/#/song?id=xxx
+ MNE("网易云音乐歌曲详情",
+ compile("https://music\\.163\\.com/(#/)?song\\?id=(?.+)"),
"https://music.163.com/#/song?id={shareKey}",
MnesTool.MneTool.class),
// https://c6.y.qq.com/base/fcgi-bin/u?__=xxx
MQQS("QQ音乐分享",
- "https://(.+)\\.y\\.qq\\.com/base/fcgi-bin/u\\?__=(.+)",
+ compile("https://(.+)\\.y\\.qq\\.com/base/fcgi-bin/u\\?__=(?.+)"),
"https://c6.y.qq.com/base/fcgi-bin/u?__={shareKey}",
- MqqTool.class),
+ MqqsTool.class),
// https://y.qq.com/n/ryqq/songDetail/000XjcLg0fbRjv?songtype=0
- MQQ("QQ音乐",
- "https://y\\.qq\\.com/n/ryqq/songDetail/(.+)\\?.*",
+ MQQ("QQ音乐歌曲详情",
+ compile("https://y\\.qq\\.com/n/ryqq/songDetail/(?.+)(\\?.*)?"),
"https://y.qq.com/n/ryqq/songDetail/{shareKey}",
- MqqTool.class),
+ MqqsTool.MqqTool.class),
// https://t1.kugou.com/song.html?id=xxx
MKGS("酷狗音乐分享",
- "https://(.+)\\.kugou\\.com/song\\.html\\?id=(.+)",
+ compile("https://(.+)\\.kugou\\.com/song\\.html\\?id=(?.+)"),
"https://t1.kugou.com/song.html?id={shareKey}",
MkgsTool.class),
// https://www.kugou.com/share/2bi8Fe9CSV3.html?id=2bi8Fe9CSV3#6ed9gna4"
MKGS2("酷狗音乐分享2",
- "https://www\\.kugou\\.com/share/(.+).html\\?.*",
+ compile("https://(.+)\\.kugou\\.com/share/(?.+).html.*"),
"https://www.kugou.com/share/{shareKey}.html",
MkgsTool.Mkgs2Tool.class),
// https://www.kugou.com/mixsong/2bi8Fe9CSV3
- MKG("酷狗音乐",
- "https://(.+)\\.kugou\\.com/song\\.html\\?id=(.+)",
- "https://www.kugou.com/mixsong/{shareKey}",
+ MKG("酷狗音乐歌曲详情",
+ compile("https://(.+)\\.kugou\\.com/mixsong/(?.+)\\.html.*"),
+ "https://www.kugou.com/mixsong/{shareKey}.html",
MkgsTool.MkgTool.class),
- //
+ // https://kuwo.cn/play_detail/395500809
MKWS("酷我音乐分享*",
- "https://(.+)\\.kugou\\.com/song\\.html\\?id=(.+)",
- "https://t1.kugou.com/song.html?id={shareKey}",
+ compile("https://kuwo\\.cn/play_detail/(?.+)"),
+ "https://kuwo.cn/play_detail/{shareKey}",
MkwTool.class),
- //
+ // https://music.migu.cn/v3/music/song/6326951FKBJ?channelId=001002H
MMGS("咪咕音乐分享",
- "https://(.+)\\.kugou\\.com/song\\.html\\?id=(.+)",
- "https://t1.kugou.com/song.html?id={shareKey}",
+ compile("https://music\\.migu\\.cn/v3/music/song/(?.+)(\\?.*)?"),
+ "https://music.migu.cn/v3/music/song/{shareKey}",
MkwTool.class),
// =====================私有盘解析==========================
+
+ // Cloudreve自定义域名解析, 解析器CeTool兜底策略, 即任意域名如果匹配不到对应的规则, 则由CeTool统一处理,
+ // 如果不属于Cloudreve盘 则调用下一个自定义域名解析器, 若都处理不了则抛出异常, 这种匹配模式类似责任链
// https://pan.huang1111.cn/s/xxx
// 通用域名([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}
CE("Cloudreve",
- "https://([a-z0-9]+(-[a-z0-9]+)*\\.)+[a-z]{2,}/s/(.+)",
- "https://{CloudreveDomainName}/s/{shareKey}",
- CeTool.class);
+ compile("https://([a-zA-Z0-9]+(-[a-zA-Z0-9]+)*\\.)+[a-zA-Z]{2,}(/s)?/(?.+)"),
+ "https://{any}/s/{shareKey}",
+ CeTool.class),
+ // 可道云自定义域名解析
+ KD("可道云",
+ compile("http(s)?://([a-zA-Z0-9]+(-[a-zA-Z0-9]+)*\\.)+[a-zA-Z]{2,}(/#s)?/(?.+)"),
+ "https://{any}/#s/{shareKey}",
+ KdTool.class),
+ // 其他自定义域名解析
+ OTHER("其他网盘",
+ compile("http(s)?://([a-zA-Z0-9]+(-[a-zA-Z0-9]+)*\\.)+[a-zA-Z]{2,}/(?.+)"),
+ "https://{any}/{shareKey}",
+ OtherTool.class);
+ public static final String KEY = "KEY";
// 网盘的显示名称,用于用户界面显示
private final String displayName;
// 用于匹配和解析分享链接的正则表达式,保证最后一个捕捉组能匹配到分享key
- private final String regexPattern;
+ private final Pattern pattern;
+
+ private final String regex;
// 网盘的标准链接模板,不含占位符,用于规范化分享链接
private final String standardUrlTemplate;
@@ -147,10 +168,11 @@ public enum PanDomainTemplate {
// 指向解析工具IPanTool实现类
private final Class extends IPanTool> toolClass;
- PanDomainTemplate(String displayName, String regexPattern, String standardUrlTemplate,
+ PanDomainTemplate(String displayName, Pattern pattern, String standardUrlTemplate,
Class extends IPanTool> toolClass) {
this.displayName = displayName;
- this.regexPattern = regexPattern;
+ this.pattern = pattern;
+ this.regex = pattern.pattern();
this.standardUrlTemplate = standardUrlTemplate;
this.toolClass = toolClass;
}
@@ -159,8 +181,12 @@ public enum PanDomainTemplate {
return displayName;
}
- public String getRegexPattern() {
- return regexPattern;
+ public Pattern getPattern() {
+ return pattern;
+ }
+
+ public String getRegex() {
+ return regex;
}
public String getStandardUrlTemplate() {
@@ -174,7 +200,7 @@ public enum PanDomainTemplate {
public static void main(String[] args) {
// 校验重复
Set collect =
- Arrays.stream(PanDomainTemplate.values()).map(PanDomainTemplate::getRegexPattern).collect(Collectors.toSet());
+ Arrays.stream(PanDomainTemplate.values()).map(PanDomainTemplate::getRegex).collect(Collectors.toSet());
if (collect.size()QAIU
- * @date 2023/6/13 4:26
- */
-public enum PanType {
- LZ("lz"),
- COW("cow");
-
- PanType(String type) {
- }
-}
diff --git a/parser/src/main/java/cn/qaiu/parser/ParserCreate.java b/parser/src/main/java/cn/qaiu/parser/ParserCreate.java
index 38c4aee..c13d3c1 100644
--- a/parser/src/main/java/cn/qaiu/parser/ParserCreate.java
+++ b/parser/src/main/java/cn/qaiu/parser/ParserCreate.java
@@ -4,7 +4,8 @@ import cn.qaiu.entity.ShareLinkInfo;
import org.apache.commons.lang3.StringUtils;
import java.util.regex.Matcher;
-import java.util.regex.Pattern;
+
+import static cn.qaiu.parser.PanDomainTemplate.KEY;
/**
@@ -34,15 +35,14 @@ public class ParserCreate {
if (StringUtils.isEmpty(shareUrl)) {
throw new IllegalArgumentException("ShareLinkInfo shareUrl is empty");
}
- Pattern pattern = Pattern.compile(this.panDomainTemplate.getRegexPattern());
- Matcher matcher = pattern.matcher(shareUrl);
+ Matcher matcher = this.panDomainTemplate.getPattern().matcher(shareUrl);
if (matcher.find()) {
- String shareKey = matcher.group(matcher.groupCount());
+ String shareKey = matcher.group(KEY);
// 返回规范化的标准链接
String standardUrl = getStandardUrlTemplate().replace("{shareKey}", shareKey);
shareLinkInfo.setShareUrl(shareUrl);
shareLinkInfo.setShareKey(shareKey);
- if (!(panDomainTemplate == PanDomainTemplate.CE)) {
+ if (!(panDomainTemplate.ordinal() >= PanDomainTemplate.CE.ordinal())) {
shareLinkInfo.setStandardUrl(standardUrl);
}
return this;
@@ -68,7 +68,7 @@ public class ParserCreate {
// set share key
public ParserCreate shareKey(String shareKey) {
- if (panDomainTemplate == PanDomainTemplate.CE) {
+ if (panDomainTemplate.ordinal() >= PanDomainTemplate.CE.ordinal()) {
// 处理Cloudreve(ce)类: pan.huang1111.cn_s_wDz5TK _ -> /
String[] s = shareKey.split("_");
String standardUrl = "https://" + String.join("/", s);
@@ -82,6 +82,13 @@ public class ParserCreate {
return this;
}
+ // set any share url
+ public ParserCreate fromAnyShareUrl(String url) {
+ shareLinkInfo.setStandardUrl(url);
+ shareLinkInfo.setShareUrl(url);
+ return this;
+ }
+
public String getStandardUrlTemplate() {
return this.panDomainTemplate.getStandardUrlTemplate();
}
@@ -98,12 +105,12 @@ public class ParserCreate {
// 根据分享链接获取PanDomainTemplate实例
public synchronized static ParserCreate fromShareUrl(String shareUrl) {
for (PanDomainTemplate panDomainTemplate : PanDomainTemplate.values()) {
- if (shareUrl.matches(panDomainTemplate.getRegexPattern())) {
+ if (panDomainTemplate.getPattern().matcher(shareUrl).matches()) {
ShareLinkInfo shareLinkInfo = ShareLinkInfo.newBuilder()
.type(panDomainTemplate.name().toLowerCase())
.panName(panDomainTemplate.getDisplayName())
.shareUrl(shareUrl).build();
- if (panDomainTemplate == PanDomainTemplate.CE) {
+ if (panDomainTemplate.ordinal() >= PanDomainTemplate.CE.ordinal()) {
shareLinkInfo.setStandardUrl(shareUrl);
}
ParserCreate parserCreate = new ParserCreate(panDomainTemplate, shareLinkInfo);
@@ -119,6 +126,7 @@ public class ParserCreate {
PanDomainTemplate panDomainTemplate = Enum.valueOf(PanDomainTemplate.class, type.toUpperCase());
ShareLinkInfo shareLinkInfo = ShareLinkInfo.newBuilder()
.type(type.toLowerCase()).build();
+ shareLinkInfo.setPanName(panDomainTemplate.getDisplayName());
return new ParserCreate(panDomainTemplate, shareLinkInfo);
} catch (IllegalArgumentException ignore) {
// 如果没有找到对应的枚举实例,抛出异常
diff --git a/parser/src/main/java/cn/qaiu/parser/impl/CeTool.java b/parser/src/main/java/cn/qaiu/parser/impl/CeTool.java
index 88245a7..666b17e 100644
--- a/parser/src/main/java/cn/qaiu/parser/impl/CeTool.java
+++ b/parser/src/main/java/cn/qaiu/parser/impl/CeTool.java
@@ -1,13 +1,17 @@
package cn.qaiu.parser.impl;
-import cn.qaiu.entity.ShareLinkInfo;
+import cn.qaiu.entity.ShareLinkInfo;
import cn.qaiu.parser.PanBase;
+import cn.qaiu.parser.PanDomainTemplate;
+import cn.qaiu.parser.ParserCreate;
import io.vertx.core.Future;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.client.HttpRequest;
import java.net.URL;
+import java.util.Arrays;
+import java.util.Iterator;
/**
* Cloudreve自建网盘解析
@@ -42,22 +46,32 @@ public class CeTool extends PanBase {
String downloadApiUrl = url.getProtocol() + "://" + url.getHost() + DOWNLOAD_API_PATH + key + "?path" +
"=undefined/undefined;";
String shareApiUrl = url.getProtocol() + "://" + url.getHost() + SHARE_API_PATH + key;
-
// 设置cookie
HttpRequest httpRequest = clientSession.getAbs(shareApiUrl);
if (pwd != null) {
httpRequest.addQueryParam("password", pwd);
}
// 获取下载链接
- httpRequest.send().onSuccess(res -> getDownURL(downloadApiUrl)).onFailure(handleFail(shareApiUrl));
+ httpRequest.send().onSuccess(res -> {
+ try {
+ if (res.statusCode() == 200 && res.bodyAsJsonObject().containsKey("code")) {
+ getDownURL(downloadApiUrl);
+ } else {
+ nextParser();
+ }
+ } catch (Exception e) {
+ nextParser();
+ }
+ }).onFailure(handleFail(shareApiUrl));
} catch (Exception e) {
fail(e, "URL解析错误");
}
return promise.future();
}
- private void getDownURL(String apiUrl) {
- clientSession.putAbs(apiUrl).send().onSuccess(res -> {
+
+ private void getDownURL(String shareApiUrl) {
+ clientSession.putAbs(shareApiUrl).send().onSuccess(res -> {
JsonObject jsonObject = asJson(res);
System.out.println(jsonObject.encodePrettily());
if (jsonObject.containsKey("code") && jsonObject.getInteger("code") == 0) {
@@ -65,6 +79,6 @@ public class CeTool extends PanBase {
} else {
fail("JSON解析失败: {}", jsonObject.encodePrettily());
}
- }).onFailure(handleFail(apiUrl));
+ }).onFailure(handleFail(shareApiUrl));
}
}
diff --git a/parser/src/main/java/cn/qaiu/parser/impl/KdTool.java b/parser/src/main/java/cn/qaiu/parser/impl/KdTool.java
new file mode 100644
index 0000000..83a5da0
--- /dev/null
+++ b/parser/src/main/java/cn/qaiu/parser/impl/KdTool.java
@@ -0,0 +1,26 @@
+package cn.qaiu.parser.impl;
+
+import cn.qaiu.entity.ShareLinkInfo;
+import cn.qaiu.parser.PanBase;
+import io.vertx.core.Future;
+import io.vertx.core.json.JsonArray;
+import io.vertx.core.json.JsonObject;
+
+import java.util.UUID;
+
+/**
+ * 可道云
+ */
+public class KdTool extends PanBase {
+ private static final String API_URL_PREFIX = "";
+
+ public KdTool(ShareLinkInfo shareLinkInfo) {
+ super(shareLinkInfo);
+ }
+
+ public Future parse() {
+ nextParser();
+ // TODO
+ return future();
+ }
+}
diff --git a/parser/src/main/java/cn/qaiu/parser/impl/MmgTool.java b/parser/src/main/java/cn/qaiu/parser/impl/MmgTool.java
index 07aa2cc..9918497 100644
--- a/parser/src/main/java/cn/qaiu/parser/impl/MmgTool.java
+++ b/parser/src/main/java/cn/qaiu/parser/impl/MmgTool.java
@@ -3,7 +3,6 @@ package cn.qaiu.parser.impl;
import cn.qaiu.entity.ShareLinkInfo;
import cn.qaiu.parser.PanBase;
import io.vertx.core.Future;
-import io.vertx.uritemplate.UriTemplate;
/**
* 咪咕音乐分享
@@ -20,6 +19,8 @@ public class MmgTool extends PanBase {
public Future parse() {
String shareUrl = shareLinkInfo.getStandardUrl();
+ // TODO
+ promise.complete("暂未实现, 敬请期待");
return promise.future();
}
}
diff --git a/parser/src/main/java/cn/qaiu/parser/impl/MnesTool.java b/parser/src/main/java/cn/qaiu/parser/impl/MnesTool.java
index fbebd99..058a5c5 100644
--- a/parser/src/main/java/cn/qaiu/parser/impl/MnesTool.java
+++ b/parser/src/main/java/cn/qaiu/parser/impl/MnesTool.java
@@ -34,7 +34,12 @@ public class MnesTool extends PanBase {
String id = URLUtil.from(locationURL).getParam("id");
clientNoRedirects.getAbs(UriTemplate.of(API_URL)).setTemplateParam("id", id).send()
.onSuccess(res2 -> {
- promise.complete(res2.headers().get("Location"));
+ String location = res2.headers().get("Location");
+ if (location.endsWith("/404")) {
+ fail("链接已失效: id={}", id);
+ } else {
+ promise.complete(location);
+ }
}).onFailure(handleFail(API_URL.replace("{id}", id)));
}
diff --git a/parser/src/main/java/cn/qaiu/parser/impl/MqqTool.java b/parser/src/main/java/cn/qaiu/parser/impl/MqqsTool.java
similarity index 57%
rename from parser/src/main/java/cn/qaiu/parser/impl/MqqTool.java
rename to parser/src/main/java/cn/qaiu/parser/impl/MqqsTool.java
index 48a7560..6d1da84 100644
--- a/parser/src/main/java/cn/qaiu/parser/impl/MqqTool.java
+++ b/parser/src/main/java/cn/qaiu/parser/impl/MqqsTool.java
@@ -14,7 +14,7 @@ import io.vertx.uritemplate.UriTemplate;
* 分享示例
* 详情页
*/
-public class MqqTool extends PanBase {
+public class MqqsTool extends PanBase {
public static final String API_URL = "https://u.y.qq.com/cgi-bin/musicu" +
".fcg?-=getplaysongvkey2682247447678878&g_tk=5381&loginUin=956581739&hostUin=0&format=json&inCharset=utf8" +
@@ -24,7 +24,7 @@ public class MqqTool extends PanBase {
"%2C%22loginflag%22%3A1%2C%22platform%22%3A%2220%22%7D%7D%2C%22comm%22%3A%7B%22uin%22%3A956581739%2C" +
"%22format%22%3A%22json%22%2C%22ct%22%3A24%2C%22cv%22%3A0%7D%7D";
- public MqqTool(ShareLinkInfo shareLinkInfo) {
+ public MqqsTool(ShareLinkInfo shareLinkInfo) {
super(shareLinkInfo);
}
@@ -36,30 +36,43 @@ public class MqqTool extends PanBase {
clientNoRedirects.getAbs(shareUrl).send().onSuccess(res -> {
String locationURL = res.headers().get("Location");
String id = URLUtil.from(locationURL).getParam("songmid");
- clientNoRedirects.getAbs(UriTemplate.of(API_URL)).setTemplateParam("songmid", id).send().onSuccess(res2 -> {
- JsonObject jsonObject = asJson(res2);
- System.out.println(jsonObject.encodePrettily());
- try {
- JsonObject data = jsonObject.getJsonObject("req_0").getJsonObject("data");
- String path = data.getJsonArray("midurlinfo").getJsonObject(0).getString("purl");
- if (path.isEmpty()) {
- fail("暂不支持VIP音乐");
- return;
- }
- String downURL = data.getJsonArray("sip").getString(0)
- .replace("http://", "https://") + path;
- System.out.println(downURL);
- promise.complete(downURL);
- } catch (Exception e) {
- fail("获取失败");
- }
- }).onFailure(handleFail(API_URL.replace("{id}", id)));
+ downUrl(id);
}).onFailure(handleFail(shareUrl));
return promise.future();
}
- public static void main(String[] args) {
- new MqqTool(ShareLinkInfo.newBuilder().build()).parse();
+ protected void downUrl(String id) {
+ clientNoRedirects.getAbs(UriTemplate.of(API_URL)).setTemplateParam("songmid", id).send().onSuccess(res2 -> {
+ JsonObject jsonObject = asJson(res2);
+ log.debug(jsonObject.encodePrettily());
+ try {
+ JsonObject data = jsonObject.getJsonObject("req_0").getJsonObject("data");
+ String path = data.getJsonArray("midurlinfo").getJsonObject(0).getString("purl");
+ if (path.isEmpty()) {
+ fail("暂不支持VIP音乐");
+ return;
+ }
+ String downURL = data.getJsonArray("sip").getString(0)
+ .replace("http://", "https://") + path;
+ promise.complete(downURL);
+ } catch (Exception e) {
+ fail("获取失败");
+ }
+ }).onFailure(handleFail(API_URL.replace("{id}", id)));
+ }
+
+
+ public static class MqqTool extends MqqsTool{
+
+ public MqqTool(ShareLinkInfo shareLinkInfo) {
+ super(shareLinkInfo);
+ }
+
+ @Override
+ public Future parse() {
+ downUrl(shareLinkInfo.getShareKey());
+ return promise.future();
+ }
}
}
diff --git a/parser/src/main/java/cn/qaiu/parser/impl/OtherTool.java b/parser/src/main/java/cn/qaiu/parser/impl/OtherTool.java
new file mode 100644
index 0000000..6905727
--- /dev/null
+++ b/parser/src/main/java/cn/qaiu/parser/impl/OtherTool.java
@@ -0,0 +1,22 @@
+package cn.qaiu.parser.impl;
+
+import cn.qaiu.entity.ShareLinkInfo;
+import cn.qaiu.parser.PanBase;
+import io.vertx.core.Future;
+
+/**
+ * 其他网盘解析
+ */
+public class OtherTool extends PanBase {
+ private static final String API_URL_PREFIX = "";
+
+ public OtherTool(ShareLinkInfo shareLinkInfo) {
+ super(shareLinkInfo);
+ }
+
+ public Future parse() {
+ // TODO
+ fail("暂未实现, 敬请期待");
+ return future();
+ }
+}
diff --git a/parser/src/main/java/cn/qaiu/util/URLUtil.java b/parser/src/main/java/cn/qaiu/util/URLUtil.java
index 1b38a31..916a27f 100644
--- a/parser/src/main/java/cn/qaiu/util/URLUtil.java
+++ b/parser/src/main/java/cn/qaiu/util/URLUtil.java
@@ -1,25 +1,32 @@
package cn.qaiu.util;
+import org.apache.commons.lang3.StringUtils;
+
import java.net.URL;
import java.net.URLDecoder;
+import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
public class URLUtil {
- private Map queryParams = new HashMap<>();
+ private final Map queryParams = new HashMap<>();
// 构造函数,传入URL并解析参数
private URLUtil(String url) {
try {
URL parsedUrl = new URL(url);
+ String ref = parsedUrl.getRef();
+ if (StringUtils.isNotEmpty(ref)) {
+ parsedUrl = new URL(parsedUrl.getProtocol() + "://" + parsedUrl.getHost() + ref);
+ }
String query = parsedUrl.getQuery();
if (query != null) {
String[] pairs = query.split("&");
for (String pair : pairs) {
String[] keyValue = pair.split("=");
- String key = URLDecoder.decode(keyValue[0], "UTF-8");
- String value = keyValue.length > 1 ? URLDecoder.decode(keyValue[1], "UTF-8") : "";
+ String key = URLDecoder.decode(keyValue[0], StandardCharsets.UTF_8);
+ String value = keyValue.length > 1 ? URLDecoder.decode(keyValue[1], StandardCharsets.UTF_8) : "";
queryParams.put(key, value);
}
}
diff --git a/parser/src/test/java/cn/qaiu/util/TestRegex.java b/parser/src/test/java/cn/qaiu/util/TestRegex.java
index 610f834..90e7916 100644
--- a/parser/src/test/java/cn/qaiu/util/TestRegex.java
+++ b/parser/src/test/java/cn/qaiu/util/TestRegex.java
@@ -10,11 +10,10 @@ public class TestRegex {
@Test
public void regexYFC() {
String html = """
-
-
+ https://www.kugou.com/mixsong/9q98o5b9.html
""";
- Pattern compile = Pattern.compile("id=\"typed_id\"\\s+value=\"file_(\\d+)\"");
+ Pattern compile = Pattern.compile("https://(.+)\\.kugou\\.com/mixsong/(?.+).html");
Matcher matcher = compile.matcher(html);
if (matcher.find()) {
System.out.println(matcher.group(0));
diff --git a/web-service/src/main/java/cn/qaiu/lz/common/util/URLParamUtil.java b/web-service/src/main/java/cn/qaiu/lz/common/util/URLParamUtil.java
index 168561e..66972a0 100644
--- a/web-service/src/main/java/cn/qaiu/lz/common/util/URLParamUtil.java
+++ b/web-service/src/main/java/cn/qaiu/lz/common/util/URLParamUtil.java
@@ -28,10 +28,6 @@ public class URLParamUtil {
if (params.contains("url")) {
String encodedUrl = params.get("url");
url = handleTruncatedUrl(encodedUrl, params);
- if (url.endsWith(".html")) {
- // 123云盘的后缀处理
- url = url.replace(".html", "");
- }
}
return url;
}
diff --git a/web-service/src/main/resources/http-tools/pan-mne.http b/web-service/src/main/resources/http-tools/pan-mne.http
index 647c121..01c2ad4 100644
--- a/web-service/src/main/resources/http-tools/pan-mne.http
+++ b/web-service/src/main/resources/http-tools/pan-mne.http
@@ -8,7 +8,10 @@ https://music.163.com/song?id=233334
###
#@no-redirect
-https://music.163.com/song/media/outer/url?id=233334
+https://music.163.com/song/media/outer/url?id=2020593612
+
+###
+https://music.163.com/#/song?id=092087
###
@@ -166,3 +169,13 @@ https://ws6.stream.qqmusic.qq.com/C400003mAan70zUy5O.m4a?guid=2796982635&vkey=B2
###
https://ws.stream.qqmusic.qq.com/C400003mAan70zUy5O.m4a?fromtag=666&guid=2796982635&vkey=B2EDD08E318F0C0D2B3A9462FC5754CBCA9AEFD796FA0662C83A102821425D31547F957451751901F195095830842E1565FF8815B210B25A
+
+###
+https://y.qq.com/n/ryqq/songDetail/000KKjzb2Eq15b
+
+###
+# @no-redirect
+https://c6.y.qq.com/base/fcgi-bin/u?__=k8gafY6HAQ5Y
+
+###
+https://u.y.qq.com/cgi-bin/musicu.fcg?-=getplaysongvkey2682247447678878&g_tk=5381&loginUin=956581739&hostUin=0&format=json&inCharset=utf8&outCharset=utf-8¬ice=0&platform=yqq.json&needNewCode=0&data=%7B%22req_0%22%3A%7B%22module%22%3A%22vkey.GetVkeyServer%22%2C%22method%22%3A%22CgiGetVkey%22%2C%22param%22%3A%7B%22guid%22%3A%222796982635%22%2C%22songmid%22%3A%5B%22000KKjzb2Eq15b%22%5D%2C%22songtype%22%3A%5B1%5D%2C%22uin%22%3A%22956581739%22%2C%22loginflag%22%3A1%2C%22platform%22%3A%2220%22%7D%7D%2C%22comm%22%3A%7B%22uin%22%3A956581739%2C%22format%22%3A%22json%22%2C%22ct%22%3A24%2C%22cv%22%3A0%7D%7D
diff --git a/web-service/src/main/resources/http-tools/temp.http b/web-service/src/main/resources/http-tools/temp.http
index 7cc3e5d..619e726 100644
--- a/web-service/src/main/resources/http-tools/temp.http
+++ b/web-service/src/main/resources/http-tools/temp.http
@@ -64,3 +64,15 @@ sec-fetch-user: ?1
upgrade-insecure-requests: 1
user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36
Content-Type: application/x-www-form-urlencoded
+
+###
+GET https://blog.qaiu.top/api/v3/share/download/nLNsQ
+
+###
+# @no-redirect
+GET http://127.0.0.1:6401/parser?url=https://blog.qaiu.top/s/nLNsQ1
+
+###
+# @no-redirect
+GET http://127.0.0.1:6401/parser?url=https://pan.seeoss.com/s/nLNsQ1
+
diff --git a/web-service/src/main/resources/http-tools/test.http b/web-service/src/main/resources/http-tools/test.http
index 6ed1fa5..e493e68 100644
--- a/web-service/src/main/resources/http-tools/test.http
+++ b/web-service/src/main/resources/http-tools/test.http
@@ -153,8 +153,14 @@ GET http://127.0.0.1:6400/json/ce/pan.huang1111.cn_s_g31PcQ@qaiu
#GET http://127.0.0.1:6400/parser?url=https://pan.huang1111.cn/s/g31PcQ&pwd=qaiu
# @no-redirect
-GET http://127.0.0.1:6400/parser?url=https://pan.seeoss.com/s/nLNsQ
+GET http://127.0.0.1:6401/parser?url=https://pan.seeoss.com/s/nLNsQ
+###
+# @no-redirect
+GET http://127.0.0.1:6401/parser?url=https://blog.qaiu.top/s/nLNsQ
+
+###
+PUT https://blog.qaiu.top/s/nLNsQ
### PASS QQ
@@ -197,15 +203,37 @@ GET http://127.0.0.1:6401/parser?url=https://474b.com/file/4015376-131945810
### PASS MNE
# @no-redirect
-GET http://127.0.0.1:6401/parser?url=http://163cn.tv/ykLZJJT
+GET http://127.0.0.1:6401/json/parser?url=http://163cn.tv/ykLZJJT
+### PASS MNE2
+# @no-redirect
+GET http://127.0.0.1:6401/parser?url=https://music.163.com/#/song?id=472194327
+
### PASS MQQ
# @no-redirect
GET http://127.0.0.1:6401/parser?url=https://c6.y.qq.com/base/fcgi-bin/u?__=k8gafY6HAQ5Y
+### PASS MQQ2
+# @no-redirect
+GET http://127.0.0.1:6401/parser?url=https://y.qq.com/n/ryqq/songDetail/000KKjzb2Eq15b
+### PASS MKG0 酷狗
+# @no-redirect
+GET http://127.0.0.1:6401/parser?url=https://www.kugou.com/share/2bi8Fe9CSV3.html
### PASS MKG
# @no-redirect
+GET http://127.0.0.1:6401/json/parser?url=https://www.kugou.com/share/2bi8Fe9CSV3.html?id=2bi8Fe9CSV3#6ed9gna4
+### PASS MKG2
+# @no-redirect
GET http://127.0.0.1:6401/parser?url=https://t1.kugou.com/song.html?id=2bi8Fe9CSV3
+### PASS MKG3
+# @no-redirect
+GET http://127.0.0.1:6401/parser?url=https://www.kugou.com/mixsong/9q98o5b9.html
+
+### PASS MQW 酷我
+# @no-redirect
+GET http://127.0.0.1:6401/parser?url=https://kuwo.cn/play_detail/395500809
+
+
### n1
http://127.0.0.1:6401/n1/statisticsInfo