Compare commits

..

5 Commits

Author SHA1 Message Date
q
cb9dbfcc69 蓝奏云规则更新 2026-02-01 10:33:25 +08:00
qaiu
42b366ed0f Clean up launch configurations in launch.json,run AppMain
Removed unused Java launch configurations from launch.json.
2026-01-27 07:53:20 +08:00
qaiu
4021c507b6 更新 README.md, 添加接口文档https://nfdparser.apifox.cn 2026-01-27 00:05:56 +08:00
qaiu
4d8e82080d 189.qaiu.top 大文件解析体验版,支持天翼云盘,移动云盘等
#153 #156 #119 #92
2026-01-26 13:47:37 +08:00
qaiu
fca608b44e 更新 README.md
天翼云盘演示站限时体验
2026-01-26 13:09:49 +08:00
4 changed files with 99 additions and 103 deletions

54
.vscode/launch.json vendored
View File

@@ -1,7 +1,4 @@
{ {
// 使用 IntelliSense 了解相关属性。
// 悬停以查看现有属性的描述。
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0", "version": "0.2.0",
"configurations": [ "configurations": [
{ {
@@ -10,61 +7,12 @@
"request": "launch", "request": "launch",
"mainClass": "${file}" "mainClass": "${file}"
}, },
{
"type": "java",
"name": "StringCase",
"request": "launch",
"mainClass": "cn.qaiu.vx.core.util.StringCase",
"projectName": "core"
},
{
"type": "java",
"name": "FCURLParser",
"request": "launch",
"mainClass": "cn.qaiu.parser.FCURLParser",
"projectName": "parser"
},
{
"type": "java",
"name": "QkTool",
"request": "launch",
"mainClass": "cn.qaiu.parser.impl.QkTool",
"projectName": "parser"
},
{
"type": "java",
"name": "WebClientExample",
"request": "launch",
"mainClass": "qaiu.web.test.WebClientExample",
"projectName": "parser"
},
{ {
"type": "java", "type": "java",
"name": "AppMain", "name": "AppMain",
"request": "launch", "request": "launch",
"mainClass": "cn.qaiu.lz.AppMain", "mainClass": "cn.qaiu.lz.AppMain",
"projectName": "web-service" "projectName": "web-service"
},
{
"type": "java",
"name": "TestJs",
"request": "launch",
"mainClass": "cn.qaiu.web.test.TestJs",
"projectName": "web-service"
},
{
"type": "java",
"name": "TestOS",
"request": "launch",
"mainClass": "cn.qaiu.web.test.TestOS",
"projectName": "web-service"
},
{
"type": "java",
"name": "WebProxyExamples",
"request": "launch",
"mainClass": "cn.qaiu.web.test.WebProxyExamples",
"projectName": "web-service"
} }
] ]
} }

View File

@@ -14,7 +14,7 @@
# netdisk-fast-download 网盘分享链接云解析服务 # netdisk-fast-download 网盘分享链接云解析服务
QQ群1017480890 QQ交流1017480890
netdisk-fast-download网盘直链云解析(nfd云解析)能把网盘分享下载链接转化为直链,支持多款云盘,已支持蓝奏云/蓝奏云优享/奶牛快传/移动云云空间/小飞机盘/亿方云/123云盘/Cloudreve等支持加密分享以及部分网盘文件夹分享。 netdisk-fast-download网盘直链云解析(nfd云解析)能把网盘分享下载链接转化为直链,支持多款云盘,已支持蓝奏云/蓝奏云优享/奶牛快传/移动云云空间/小飞机盘/亿方云/123云盘/Cloudreve等支持加密分享以及部分网盘文件夹分享。
@@ -45,7 +45,7 @@ https://nfd-parser.github.io/nfd-preview/preview.html?src=https%3A%2F%2Flz.qaiu.
## 预览地址 ## 预览地址
[预览地址1](https://lz.qaiu.top) [预览地址1](https://lz.qaiu.top)
[预览地址2](https://lz0.qaiu.top) [预览地址2](https://lz0.qaiu.top)
[移动/联通/天翼云盘大文件试用](https://189.qaiu.top) [天翼云盘/移动云盘限时体验](https://189.qaiu.top)
main分支依赖JDK17, 提供了JDK11分支[main-jdk11](https://github.com/qaiu/netdisk-fast-download/tree/main-jdk11) main分支依赖JDK17, 提供了JDK11分支[main-jdk11](https://github.com/qaiu/netdisk-fast-download/tree/main-jdk11)
**0.1.8及以上版本json接口格式有调整 参考json返回数据格式示例** **0.1.8及以上版本json接口格式有调整 参考json返回数据格式示例**
@@ -94,6 +94,8 @@ main分支依赖JDK17, 提供了JDK11分支[main-jdk11](https://github.com/qaiu/
- [天翼云盘-p189](https://cloud.189.cn/) - [天翼云盘-p189](https://cloud.189.cn/)
## API接口 ## API接口
[api接口文档](https://nfdparser.apifox.cn/)
### 服务端口 ### 服务端口
- **6400**: API 服务端口(建议使用 Nginx 代理) - **6400**: API 服务端口(建议使用 Nginx 代理)

View File

@@ -104,7 +104,7 @@ public enum PanDomainTemplate {
"lanzoug|" + "lanzoug|" +
"lanzoum" + "lanzoum" +
")\\.com/(.+/)?(?<KEY>.+)"), ")\\.com/(.+/)?(?<KEY>.+)"),
"https://lanzoux.com/{shareKey}", "https://w1.lanzn.com/{shareKey}",
LzTool.class), LzTool.class),
// https://www.feijix.com/s/ // https://www.feijix.com/s/

View File

@@ -11,14 +11,12 @@ 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.WebClientSession; import io.vertx.ext.web.client.WebClientSession;
import org.apache.commons.lang3.RegExUtils;
import org.openjdk.nashorn.api.scripting.ScriptObjectMirror; import org.openjdk.nashorn.api.scripting.ScriptObjectMirror;
import javax.script.ScriptException; import javax.script.ScriptException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.TreeMap;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@@ -29,13 +27,14 @@ import java.util.regex.Pattern;
*/ */
public class LzTool extends PanBase { public class LzTool extends PanBase {
public static final String SHARE_URL_PREFIX = "https://wwwwp.lanzoup.com"; WebClientSession webClientSession = WebClientSession.create(clientNoRedirects);
public static final String SHARE_URL_PREFIX = "https://w1.lanzn.com/";
MultiMap headers0 = HeaderUtils.parseHeaders(""" MultiMap headers0 = HeaderUtils.parseHeaders("""
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6 Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Cache-Control: max-age=0 Cache-Control: max-age=0
Cookie: codelen=1; pc_ad1=1
DNT: 1 DNT: 1
Priority: u=0, i Priority: u=0, i
Sec-CH-UA: "Chromium";v="140", "Not=A?Brand";v="24", "Microsoft Edge";v="140" Sec-CH-UA: "Chromium";v="140", "Not=A?Brand";v="24", "Microsoft Edge";v="140"
@@ -63,53 +62,100 @@ public class LzTool extends PanBase {
.putHeaders(headers0) .putHeaders(headers0)
.send().onSuccess(res -> { .send().onSuccess(res -> {
String html = asText(res); String html = asText(res);
try { if (html.contains("var arg1='")) {
setFileInfo(html, shareLinkInfo); webClientSession = WebClientSession.create(clientNoRedirects);
} catch (Exception e) { setCookie(html);
e.printStackTrace(); webClientSession.getAbs(sUrl)
} .putHeaders(headers0)
// 匹配iframe .send().onSuccess(res2 -> {
Pattern compile = Pattern.compile("src=\"(/fn\\?[a-zA-Z\\d_+/=]{16,})\""); String html2 = asText(res2);
Matcher matcher = compile.matcher(html); doParser(html2, pwd, sUrl);
// 没有Iframe说明是加密分享, 匹配sign通过密码请求下载页面 });
if (!matcher.find()) {
try {
String jsText = getJsByPwd(pwd, html, "document.getElementById('rpt')");
ScriptObjectMirror scriptObjectMirror = JsExecUtils.executeDynamicJs(jsText, "down_p");
getDownURL(sUrl, client, scriptObjectMirror);
} catch (Exception e) {
fail(e, "js引擎执行失败");
}
} else {
// 没有密码
String iframePath = matcher.group(1);
client.getAbs(SHARE_URL_PREFIX + iframePath).send().onSuccess(res2 -> {
String html2 = res2.bodyAsString();
// 去TMD正则 } else {
// Matcher matcher2 = Pattern.compile("'sign'\s*:\s*'(\\w+)'").matcher(html2); doParser(html, pwd, sUrl);
String jsText = getJsText(html2);
if (jsText == null) {
fail(SHARE_URL_PREFIX + iframePath + " -> " + sUrl + ": js脚本匹配失败, 可能分享已失效");
return;
}
try {
ScriptObjectMirror scriptObjectMirror = JsExecUtils.executeDynamicJs(jsText, null);
getDownURL(sUrl, client, scriptObjectMirror);
} catch (ScriptException | NoSuchMethodException e) {
fail(e, "js引擎执行失败");
}
}).onFailure(handleFail(SHARE_URL_PREFIX));
} }
}).onFailure(handleFail(sUrl)); }).onFailure(handleFail(sUrl));
return promise.future(); return promise.future();
} }
private void doParser(String html, String pwd, String sUrl) {
try {
setFileInfo(html, shareLinkInfo);
} catch (Exception e) {
e.printStackTrace();
}
// 匹配iframe
Pattern compile = Pattern.compile("src=\"(/fn\\?[a-zA-Z\\d_+/=]{16,})\"");
Matcher matcher = compile.matcher(html);
// 没有Iframe说明是加密分享, 匹配sign通过密码请求下载页面
if (!matcher.find()) {
try {
String jsText = getJsByPwd(pwd, html, "document.getElementById('rpt')");
ScriptObjectMirror scriptObjectMirror = JsExecUtils.executeDynamicJs(jsText, "down_p");
getDownURL(sUrl, scriptObjectMirror);
} catch (Exception e) {
fail(e, "js引擎执行失败");
}
}
else {
// 没有密码
String iframePath = matcher.group(1);
String absoluteURI = SHARE_URL_PREFIX + iframePath;
webClientSession.getAbs(absoluteURI).putHeaders(headers0).send().onSuccess(res2 -> {
String html2= asText(res2);
// Matcher matcher2 = Pattern.compile("'sign'\s*:\s*'(\\w+)'").matcher(html2);
String jsText = getJsText(html2);
if (jsText == null) {
headers0.add("Referer", absoluteURI);
setCookie(html2);
webClientSession.getAbs(absoluteURI).send().onSuccess(res3 -> {
String html3= asText(res3);
String jsText3 = getJsText(html3);
if (jsText3 != null) {
try {
ScriptObjectMirror scriptObjectMirror = JsExecUtils.executeDynamicJs(jsText3, null);
getDownURL(sUrl, scriptObjectMirror);
} catch (ScriptException | NoSuchMethodException e) {
fail(e, "引擎执行失败");
}
} else {
fail(SHARE_URL_PREFIX + iframePath + " -> " + sUrl + ": 获取失败0, 可能分享已失效");
return;
}
});
} else {
try {
ScriptObjectMirror scriptObjectMirror = JsExecUtils.executeDynamicJs(jsText, null);
getDownURL(sUrl, scriptObjectMirror);
} catch (ScriptException | NoSuchMethodException e) {
fail(e, "js引擎执行失败");
}
}
}).onFailure(handleFail(SHARE_URL_PREFIX));
}
}
private void setCookie(String html2) {
int beginIndex = html2.indexOf("arg1='") + 6;
String arg1 = html2.substring(beginIndex, html2.indexOf("';", beginIndex));
String acw_sc__v2 = AcwScV2Generator.acwScV2Simple(arg1);
// 创建一个 Cookie 并放入 CookieStore
DefaultCookie nettyCookie = new DefaultCookie("acw_sc__v2", acw_sc__v2);
nettyCookie.setDomain(".lanzn.com"); // 设置域名
nettyCookie.setPath("/"); // 设置路径
nettyCookie.setSecure(false);
nettyCookie.setHttpOnly(false);
webClientSession.cookieStore().put(nettyCookie);
}
private String getJsByPwd(String pwd, String html, String subText) { private String getJsByPwd(String pwd, String html, String subText) {
String jsText = getJsText(html); String jsText = getJsText(html);
if (jsText == null) { if (jsText == null) {
throw new RuntimeException("js脚本匹配失败, 可能分享已失效"); throw new RuntimeException("获取失败1, 可能分享已失效");
} }
jsText = jsText.replace("document.getElementById('pwd').value", "\"" + pwd + "\""); jsText = jsText.replace("document.getElementById('pwd').value", "\"" + pwd + "\"");
int i = jsText.indexOf(subText); int i = jsText.indexOf(subText);
@@ -131,7 +177,7 @@ public class LzTool extends PanBase {
return html.substring(startPos, endPos).replaceAll("<!--.*-->", ""); return html.substring(startPos, endPos).replaceAll("<!--.*-->", "");
} }
private void getDownURL(String key, WebClient client, Map<String, ?> obj) { private void getDownURL(String key, Map<String, ?> obj) {
if (obj == null) { if (obj == null) {
fail("需要访问密码"); fail("需要访问密码");
return; return;
@@ -163,7 +209,7 @@ public class LzTool extends PanBase {
headers.set("referer", key); headers.set("referer", key);
// action=downprocess&signs=%3Fctdf&websignkey=I5gl&sign=BWMGOF1sBTRWXwI9BjZdYVA7BDhfNAIyUG9UawJtUGMIPlAhACkCa1UyUTAAYFxvUj5XY1E7UGFXaFVq&websign=&kd=1&ves=1 // action=downprocess&signs=%3Fctdf&websignkey=I5gl&sign=BWMGOF1sBTRWXwI9BjZdYVA7BDhfNAIyUG9UawJtUGMIPlAhACkCa1UyUTAAYFxvUj5XY1E7UGFXaFVq&websign=&kd=1&ves=1
String url = SHARE_URL_PREFIX + url0; String url = SHARE_URL_PREFIX + url0;
client.postAbs(url).putHeaders(headers).sendForm(map).onSuccess(res2 -> { webClientSession.postAbs(url).putHeaders(headers).sendForm(map).onSuccess(res2 -> {
try { try {
JsonObject urlJson = asJson(res2); JsonObject urlJson = asJson(res2);
String name = urlJson.getString("inf"); String name = urlJson.getString("inf");
@@ -178,7 +224,6 @@ public class LzTool extends PanBase {
String downUrl = urlJson.getString("dom") + "/file/" + urlJson.getString("url"); String downUrl = urlJson.getString("dom") + "/file/" + urlJson.getString("url");
headers.remove("Referer"); headers.remove("Referer");
WebClientSession webClientSession = WebClientSession.create(client);
webClientSession.getAbs(downUrl).putHeaders(headers).send() webClientSession.getAbs(downUrl).putHeaders(headers).send()
.onSuccess(res3 -> { .onSuccess(res3 -> {
String location = res3.headers().get("Location"); String location = res3.headers().get("Location");
@@ -195,12 +240,13 @@ public class LzTool extends PanBase {
nettyCookie.setPath("/"); // 设置路径 nettyCookie.setPath("/"); // 设置路径
nettyCookie.setSecure(false); nettyCookie.setSecure(false);
nettyCookie.setHttpOnly(false); nettyCookie.setHttpOnly(false);
webClientSession.cookieStore().put(nettyCookie); WebClientSession webClientSession2 = WebClientSession.create(clientNoRedirects);
webClientSession.getAbs(downUrl).putHeaders(headers).send() webClientSession2.cookieStore().put(nettyCookie);
webClientSession2.getAbs(downUrl).putHeaders(headers).send()
.onSuccess(res4 -> { .onSuccess(res4 -> {
String location0 = res4.headers().get("Location"); String location0 = res4.headers().get("Location");
if (location0 == null) { if (location0 == null) {
fail(downUrl + " -> 直链获取失败, 可能分享已失效"); fail(downUrl + " -> 直链获取失败2, 可能分享已失效");
} else { } else {
setDateAndComplate(location0); setDateAndComplate(location0);
} }