From 511515cae408b7ae9ea35e9bf32f9c1a9790c84a Mon Sep 17 00:00:00 2001 From: qaiu Date: Wed, 14 Oct 2026 04:38:00 +0800 Subject: [PATCH 1/2] =?UTF-8?q?fix(iz):=20=E8=93=9D=E5=A5=8F=E4=BC=98?= =?UTF-8?q?=E4=BA=AB=E7=99=BB=E5=BD=95=E5=A4=B1=E8=B4=A5=E5=9B=9E=E9=80=80?= =?UTF-8?q?=E5=85=8D=E7=99=BB=E5=BD=95=E3=80=81TokenCache=20=E5=A4=9A?= =?UTF-8?q?=E8=B4=A6=E5=8F=B7=E3=80=81=E5=8F=AF=E9=85=8D=E7=BD=AE=20XFF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - IzTool.parse 预登录失败 recover 后继续免登录解析 - IzTool / IzToolWithAuth 登录或重登失败回退匿名下载(downloadAnonymous) - IzTool 改用 TokenCache(按 _configId/username 隔离),校验 token 前恢复 appToken 头 - 新增 IzXffHeader:-Dnfd.iz.xff / NFD_IZ_XFF = off(默认)/random/固定IP --- .../main/java/cn/qaiu/parser/impl/IzTool.java | 248 ++++++++++-------- .../cn/qaiu/parser/impl/IzToolWithAuth.java | 39 ++- .../java/cn/qaiu/parser/impl/IzXffHeader.java | 60 +++++ .../cn/qaiu/parser/impl/IzXffHeaderTest.java | 36 +++ 4 files changed, 250 insertions(+), 133 deletions(-) create mode 100644 parser/src/main/java/cn/qaiu/parser/impl/IzXffHeader.java create mode 100644 parser/src/test/java/cn/qaiu/parser/impl/IzXffHeaderTest.java diff --git a/parser/src/main/java/cn/qaiu/parser/impl/IzTool.java b/parser/src/main/java/cn/qaiu/parser/impl/IzTool.java index 6565fd4..fb0a648 100644 --- a/parser/src/main/java/cn/qaiu/parser/impl/IzTool.java +++ b/parser/src/main/java/cn/qaiu/parser/impl/IzTool.java @@ -3,6 +3,7 @@ package cn.qaiu.parser.impl; import cn.qaiu.entity.FileInfo; import cn.qaiu.entity.ShareLinkInfo; import cn.qaiu.parser.PanBase; +import cn.qaiu.parser.TokenCache; import cn.qaiu.util.AESUtils; import cn.qaiu.util.AcwScV2Generator; import cn.qaiu.util.CommonUtils; @@ -85,12 +86,31 @@ public class IzTool extends PanBase { } public IzTool(ShareLinkInfo shareLinkInfo) { super(shareLinkInfo); + IzXffHeader.apply(header); + String accountId = "_default"; + if (shareLinkInfo.getOtherParam().containsKey("auths")) { + MultiMap auths = (MultiMap) shareLinkInfo.getOtherParam().get("auths"); + if (auths.contains("_configId")) { + accountId = auths.get("_configId"); + } else if (auths.contains("username")) { + accountId = auths.get("username"); + } + } + this.cacheKey = TokenCache.key("iz", accountId); } String uuid = UUID.randomUUID().toString().toLowerCase(); // 也可以使用 UUID.randomUUID().toString() - public static volatile String token = null; - public static volatile boolean authFlag = true; + // 多账号隔离:用 TokenCache 代替 static 变量 + private final String cacheKey; + + private String token() { + return TokenCache.getToken(cacheKey); + } + + private boolean authFlag() { + return TokenCache.getFlag(cacheKey, true); + } public Future parse() { @@ -101,22 +121,21 @@ public class IzTool extends PanBase { // 检查并输出认证状态 if (shareLinkInfo.getOtherParam().containsKey("auths")) { boolean isTempAuth = shareLinkInfo.getOtherParam().containsKey("__TEMP_AUTH_ADDED"); + String token = token(); log.info("文件解析检测到认证信息: isTempAuth={}, authFlag={}, token={}", - isTempAuth, authFlag, token != null ? "已登录(" + token.substring(0, Math.min(8, token.length())) + "...)" : "未登录"); + isTempAuth, authFlag(), token != null ? "已登录(" + token.substring(0, Math.min(8, token.length())) + "...)" : "未登录"); // 如果需要认证但还没有token,先执行登录 - if ((isTempAuth || authFlag) && token == null) { + if ((isTempAuth || authFlag()) && token == null) { log.info("文件解析需要登录,开始执行登录流程..."); MultiMap auths = (MultiMap) shareLinkInfo.getOtherParam().get("auths"); return login(tsEncode, auths) - .compose(v -> { - log.info("文件解析预登录成功,继续解析流程"); - return parseWithAuth(shareId, tsEncode); + .recover(err -> { + // 预登录失败不终止解析,继续走免登录 + log.warn("文件解析预登录失败: {},使用免登录模式", err.getMessage()); + return Future.succeededFuture(); }) - .onFailure(err -> { - log.warn("文件解析预登录失败: {},尝试使用免登录模式", err.getMessage()); - // 登录失败,继续使用免登录模式 - }); + .compose(v -> parseWithAuth(shareId, tsEncode)); } else if (token != null) { log.info("文件解析使用已有token: {}...", token.substring(0, Math.min(8, token.length()))); } @@ -231,8 +250,8 @@ public class IzTool extends PanBase { // 检查是否为临时认证(临时认证每次都尝试登录) boolean isTempAuth = shareLinkInfo.getOtherParam().containsKey("__TEMP_AUTH_ADDED"); // 如果是临时认证,或者是后台配置且authFlag为true,则尝试使用认证 - if (isTempAuth || authFlag) { - log.debug("尝试使用认证信息解析, isTempAuth={}, authFlag={}", isTempAuth, authFlag); + if (isTempAuth || authFlag()) { + log.debug("尝试使用认证信息解析, isTempAuth={}, authFlag={}", isTempAuth, authFlag()); HttpRequest httpRequest = webClientSession.getAbs(UriTemplate.of(SECOND_REQUEST_URL_VIP)) .setTemplateParam("fidEncode", fidEncode) @@ -241,18 +260,19 @@ public class IzTool extends PanBase { .setTemplateParam("auth", auth) .setTemplateParam("dataKey", dataKey); MultiMap auths = (MultiMap) shareLinkInfo.getOtherParam().get("auths"); - if (token == null) { - // 执行登录 + if (token() == null) { + // 执行登录,失败则回退免登录 login(tsEncode2, auths).onFailure(failRes-> { - log.warn("登录失败: {}", failRes.getMessage()); - fail(failRes.getMessage()); + log.warn("登录失败,回退免登录: {}", failRes.getMessage()); + downloadAnonymous(fidEncode, tsEncode2, auth, dataKey); }).onSuccess(r-> { - httpRequest.setTemplateParam("appToken", token) + httpRequest.setTemplateParam("appToken", token()) .putHeaders(header); httpRequest.send().onSuccess(this::down).onFailure(handleFail("请求2")); }); } else { - // 验证token + // 验证token — 先从缓存恢复到 header + header.set("appToken", token()); webClientSession.postAbs(UriTemplate.of(TOKEN_VERIFY_URL)) .setTemplateParam("uuid", uuid) .setTemplateParam("ts", tsEncode2) @@ -260,15 +280,15 @@ public class IzTool extends PanBase { // log.info("res: {}",asJson(res)); if (asJson(res).getInteger("code") != 200) { login(tsEncode2, auths).onFailure(failRes -> { - log.warn("重新登录失败: {}", failRes.getMessage()); - fail(failRes.getMessage()); + log.warn("重新登录失败,回退免登录: {}", failRes.getMessage()); + downloadAnonymous(fidEncode, tsEncode2, auth, dataKey); }).onSuccess(r-> { - httpRequest.setTemplateParam("appToken", token) + httpRequest.setTemplateParam("appToken", token()) .putHeaders(header); httpRequest.send().onSuccess(this::down).onFailure(handleFail("请求2")); }); } else { - httpRequest.setTemplateParam("appToken", token) + httpRequest.setTemplateParam("appToken", token()) .putHeaders(header); httpRequest.send().onSuccess(this::down).onFailure(handleFail("请求2")); } @@ -277,29 +297,27 @@ public class IzTool extends PanBase { } else { // authFlag 为 false,使用免登录解析 log.debug("authFlag=false,使用免登录解析"); - webClientSession.getAbs(UriTemplate.of(SECOND_REQUEST_URL)) - .putHeaders(header) - .setTemplateParam("fidEncode", fidEncode) - .setTemplateParam("uuid", uuid) - .setTemplateParam("ts", tsEncode2) - .setTemplateParam("auth", auth) - .setTemplateParam("dataKey", dataKey).send() - .onSuccess(this::down).onFailure(handleFail("请求2")); + downloadAnonymous(fidEncode, tsEncode2, auth, dataKey); } } else { // 没有认证信息,使用免登录解析 log.debug("无认证信息,使用免登录解析"); - webClientSession.getAbs(UriTemplate.of(SECOND_REQUEST_URL)) - .putHeaders(header) - .setTemplateParam("fidEncode", fidEncode) - .setTemplateParam("uuid", uuid) - .setTemplateParam("ts", tsEncode2) - .setTemplateParam("auth", auth) - .setTemplateParam("dataKey", dataKey).send() - .onSuccess(this::down).onFailure(handleFail("请求2")); + downloadAnonymous(fidEncode, tsEncode2, auth, dataKey); } } + private void downloadAnonymous(String fidEncode, String tsEncode2, String auth, String dataKey) { + log.debug("使用免登录解析"); + webClientSession.getAbs(UriTemplate.of(SECOND_REQUEST_URL)) + .putHeaders(header) + .setTemplateParam("fidEncode", fidEncode) + .setTemplateParam("uuid", uuid) + .setTemplateParam("ts", tsEncode2) + .setTemplateParam("auth", auth) + .setTemplateParam("dataKey", dataKey).send() + .onSuccess(this::down).onFailure(handleFail("请求2")); + } + private Future login(String tsEncode2, MultiMap auths) { Promise promise1 = Promise.promise(); webClientSession.postAbs(UriTemplate.of(LOGIN_URL)) @@ -310,8 +328,13 @@ public class IzTool extends PanBase { .onSuccess(res2->{ JsonObject json = asJson(res2); if (json.getInteger("code") == 200) { - token = json.getJsonObject("data").getString("appToken"); - log.info("登录成功 token: {}...", token != null ? token.substring(0, Math.min(8, token.length())) : "null"); + String loginToken = json.getJsonObject("data").getString("appToken"); + TokenCache.putToken(cacheKey, loginToken); + TokenCache.queueCachedTokenPersist(cacheKey, loginToken, System.currentTimeMillis() + 24 * 60 * 60 * 1000L); + if (loginToken != null) { + header.set("appToken", loginToken); + } + log.info("登录成功 token: {}...", loginToken != null ? loginToken.substring(0, Math.min(8, loginToken.length())) : "null"); promise1.complete(); } else { // 检查是否为临时认证 @@ -323,7 +346,7 @@ public class IzTool extends PanBase { } else { // 后台配置的认证失败,设置authFlag并返回失败,让下次请求使用免登陆解析 log.warn("后台配置认证失败: {}, authFlag将设为false,请重新解析", json.getString("msg")); - authFlag = false; + TokenCache.putFlag(cacheKey, false); promise1.fail("认证失败: " + json.getString("msg") + ", 请重新解析将使用免登陆模式"); } } @@ -443,75 +466,75 @@ public class IzTool extends PanBase { } } - private void down(HttpResponse res2) { - MultiMap headers = res2.headers(); - String location = headers.get("Location"); - if (StringUtils.isBlank(location)) { - fail("{}", buildMissingLocationMessage(res2)); - return; - } - promise.complete(location); - } - - private String buildMissingLocationMessage(HttpResponse response) { - StringBuilder message = new StringBuilder("未获取到下载重定向地址"); - message.append(", HTTP ").append(response.statusCode()); - - String body = null; - try { - body = asText(response); - } catch (Exception e) { - body = "<响应体读取失败: " + e.getMessage() + ">"; - } - - if (StringUtils.isNotBlank(body)) { - try { - JsonObject json = new JsonObject(body); - String upstreamMsg = json.getString("msg"); - Object code = json.getValue("code"); - if (StringUtils.isNotBlank(upstreamMsg)) { - message.append(", 上游返回: ").append(upstreamMsg); - if (code != null) { - message.append(" (code=").append(code).append(")"); - } - } else { - message.append(", 响应体: ").append(previewBody(body)); - } - } catch (Exception ignored) { - message.append(", 响应体: ").append(previewBody(body)); - } - } else { - message.append(", 响应体为空"); - } - - Object fileName = shareLinkInfo.getOtherParam().get("fileName"); - Object fileSize = shareLinkInfo.getOtherParam().get("fileSizeFormat"); - if (fileName != null) { - message.append(", 文件: ").append(fileName); - } - if (fileSize != null) { - message.append(", 大小: ").append(fileSize); - } - if (!hasConfiguredAuth()) { - message.append(", 当前为免登录解析,上游可能要求登录、会员或人工处理"); - } - return message.toString(); - } - - private boolean hasConfiguredAuth() { - Object authObj = shareLinkInfo.getOtherParam().get("auths"); - if (!(authObj instanceof MultiMap auths)) { - return false; - } - return StringUtils.isNotBlank(auths.get("username")) && StringUtils.isNotBlank(auths.get("password")); - } - - private String previewBody(String body) { - int maxLength = 500; - return body.length() <= maxLength ? body : body.substring(0, maxLength) + "..."; - } - - // 目录解析 + private void down(HttpResponse res2) { + MultiMap headers = res2.headers(); + String location = headers.get("Location"); + if (StringUtils.isBlank(location)) { + fail("{}", buildMissingLocationMessage(res2)); + return; + } + promise.complete(location); + } + + private String buildMissingLocationMessage(HttpResponse response) { + StringBuilder message = new StringBuilder("未获取到下载重定向地址"); + message.append(", HTTP ").append(response.statusCode()); + + String body = null; + try { + body = asText(response); + } catch (Exception e) { + body = "<响应体读取失败: " + e.getMessage() + ">"; + } + + if (StringUtils.isNotBlank(body)) { + try { + JsonObject json = new JsonObject(body); + String upstreamMsg = json.getString("msg"); + Object code = json.getValue("code"); + if (StringUtils.isNotBlank(upstreamMsg)) { + message.append(", 上游返回: ").append(upstreamMsg); + if (code != null) { + message.append(" (code=").append(code).append(")"); + } + } else { + message.append(", 响应体: ").append(previewBody(body)); + } + } catch (Exception ignored) { + message.append(", 响应体: ").append(previewBody(body)); + } + } else { + message.append(", 响应体为空"); + } + + Object fileName = shareLinkInfo.getOtherParam().get("fileName"); + Object fileSize = shareLinkInfo.getOtherParam().get("fileSizeFormat"); + if (fileName != null) { + message.append(", 文件: ").append(fileName); + } + if (fileSize != null) { + message.append(", 大小: ").append(fileSize); + } + if (!hasConfiguredAuth()) { + message.append(", 当前为免登录解析,上游可能要求登录、会员或人工处理"); + } + return message.toString(); + } + + private boolean hasConfiguredAuth() { + Object authObj = shareLinkInfo.getOtherParam().get("auths"); + if (!(authObj instanceof MultiMap auths)) { + return false; + } + return StringUtils.isNotBlank(auths.get("username")) && StringUtils.isNotBlank(auths.get("password")); + } + + private String previewBody(String body) { + int maxLength = 500; + return body.length() <= maxLength ? body : body.substring(0, maxLength) + "..."; + } + + // 目录解析 @Override public Future> parseFileList() { Promise> promise = Promise.promise(); @@ -691,7 +714,6 @@ public class IzTool extends PanBase { } public static void resetToken() { - token = null; - authFlag = true; + TokenCache.removeByDiskType("iz"); } } diff --git a/parser/src/main/java/cn/qaiu/parser/impl/IzToolWithAuth.java b/parser/src/main/java/cn/qaiu/parser/impl/IzToolWithAuth.java index f8829aa..f43d827 100644 --- a/parser/src/main/java/cn/qaiu/parser/impl/IzToolWithAuth.java +++ b/parser/src/main/java/cn/qaiu/parser/impl/IzToolWithAuth.java @@ -84,6 +84,7 @@ public class IzToolWithAuth extends PanBase { } public IzToolWithAuth(ShareLinkInfo shareLinkInfo) { super(shareLinkInfo); + IzXffHeader.apply(header); } String uuid = UUID.randomUUID().toString().toLowerCase(); // 也可以使用 UUID.randomUUID().toString() @@ -213,8 +214,8 @@ public class IzToolWithAuth extends PanBase { if (token == null) { // 执行登录 login(tsEncode2, auths).onFailure(failRes-> { - log.warn("登录失败: {}", failRes.getMessage()); - fail(failRes.getMessage()); + log.warn("登录失败,回退免登录: {}", failRes.getMessage()); + downloadAnonymous(fidEncode, tsEncode2, auth, dataKey); }).onSuccess(r-> { httpRequest.setTemplateParam("appToken", token) .putHeaders(header); @@ -229,8 +230,8 @@ public class IzToolWithAuth extends PanBase { // log.info("res: {}",asJson(res)); if (asJson(res).getInteger("code") != 200) { login(tsEncode2, auths).onFailure(failRes -> { - log.warn("重新登录失败: {}", failRes.getMessage()); - fail(failRes.getMessage()); + log.warn("重新登录失败,回退免登录: {}", failRes.getMessage()); + downloadAnonymous(fidEncode, tsEncode2, auth, dataKey); }).onSuccess(r-> { httpRequest.setTemplateParam("appToken", token) .putHeaders(header); @@ -246,29 +247,27 @@ public class IzToolWithAuth extends PanBase { } else { // authFlag 为 false,使用免登录解析 log.debug("authFlag=false,使用免登录解析"); - webClientSession.getAbs(UriTemplate.of(SECOND_REQUEST_URL)) - .putHeaders(header) - .setTemplateParam("fidEncode", fidEncode) - .setTemplateParam("uuid", uuid) - .setTemplateParam("ts", tsEncode2) - .setTemplateParam("auth", auth) - .setTemplateParam("dataKey", dataKey).send() - .onSuccess(this::down).onFailure(handleFail("请求2")); + downloadAnonymous(fidEncode, tsEncode2, auth, dataKey); } } else { // 没有认证信息,使用免登录解析 log.debug("无认证信息,使用免登录解析"); - webClientSession.getAbs(UriTemplate.of(SECOND_REQUEST_URL)) - .putHeaders(header) - .setTemplateParam("fidEncode", fidEncode) - .setTemplateParam("uuid", uuid) - .setTemplateParam("ts", tsEncode2) - .setTemplateParam("auth", auth) - .setTemplateParam("dataKey", dataKey).send() - .onSuccess(this::down).onFailure(handleFail("请求2")); + downloadAnonymous(fidEncode, tsEncode2, auth, dataKey); } } + private void downloadAnonymous(String fidEncode, String tsEncode2, String auth, String dataKey) { + log.debug("使用免登录解析"); + webClientSession.getAbs(UriTemplate.of(SECOND_REQUEST_URL)) + .putHeaders(header) + .setTemplateParam("fidEncode", fidEncode) + .setTemplateParam("uuid", uuid) + .setTemplateParam("ts", tsEncode2) + .setTemplateParam("auth", auth) + .setTemplateParam("dataKey", dataKey).send() + .onSuccess(this::down).onFailure(handleFail("请求2")); + } + private Future login(String tsEncode2, MultiMap auths) { Promise promise1 = Promise.promise(); webClientSession.postAbs(UriTemplate.of(LOGIN_URL)) diff --git a/parser/src/main/java/cn/qaiu/parser/impl/IzXffHeader.java b/parser/src/main/java/cn/qaiu/parser/impl/IzXffHeader.java new file mode 100644 index 0000000..91746d7 --- /dev/null +++ b/parser/src/main/java/cn/qaiu/parser/impl/IzXffHeader.java @@ -0,0 +1,60 @@ +package cn.qaiu.parser.impl; + +import io.vertx.core.MultiMap; +import org.apache.commons.lang3.StringUtils; + +import java.util.concurrent.ThreadLocalRandom; + +/** + * 蓝奏云优享 X-Forwarded-For 配置。 + *

+ * 读取系统属性 {@code nfd.iz.xff},其次环境变量 {@code NFD_IZ_XFF}: + *

    + *
  • 未设置 / 空 / {@code off}:不发送该头(默认)
  • + *
  • {@code random}:每次创建解析器时随机一个国内常见网段 IP
  • + *
  • 其它值:原样作为头的值,例如 {@code 113.96.181.18}
  • + *
+ */ +public final class IzXffHeader { + + public static final String PROP = "nfd.iz.xff"; + public static final String ENV = "NFD_IZ_XFF"; + private static final String HEADER = "X-Forwarded-For"; + + /** 国内运营商常见 /8 段首字节 */ + private static final int[] CN_PREFIX = {36, 39, 42, 58, 59, 60, 61, 101, 106, 110, 111, 112, 113, 114, + 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 175, 180, 182, 183, 202, 210, 211, 218, 219, 220, 221, 222, 223}; + + private IzXffHeader() { + } + + static String configured() { + String v = System.getProperty(PROP); + if (StringUtils.isBlank(v)) { + v = System.getenv(ENV); + } + return v == null ? "" : v.trim(); + } + + /** 根据配置得到头的值,返回 null 表示不发送 */ + static String resolve(String mode) { + if (StringUtils.isBlank(mode) || "off".equalsIgnoreCase(mode)) { + return null; + } + if ("random".equalsIgnoreCase(mode)) { + ThreadLocalRandom r = ThreadLocalRandom.current(); + return CN_PREFIX[r.nextInt(CN_PREFIX.length)] + "." + r.nextInt(256) + "." + r.nextInt(256) + "." + (1 + r.nextInt(254)); + } + return mode; + } + + /** 按当前配置写入或移除请求头 */ + public static void apply(MultiMap headers) { + String value = resolve(configured()); + if (value == null) { + headers.remove(HEADER); + } else { + headers.set(HEADER, value); + } + } +} diff --git a/parser/src/test/java/cn/qaiu/parser/impl/IzXffHeaderTest.java b/parser/src/test/java/cn/qaiu/parser/impl/IzXffHeaderTest.java new file mode 100644 index 0000000..8b52bea --- /dev/null +++ b/parser/src/test/java/cn/qaiu/parser/impl/IzXffHeaderTest.java @@ -0,0 +1,36 @@ +package cn.qaiu.parser.impl; + +import io.vertx.core.MultiMap; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class IzXffHeaderTest { + @Test + public void offByDefault() { + assertNull(IzXffHeader.resolve(null)); + assertNull(IzXffHeader.resolve("")); + assertNull(IzXffHeader.resolve("OFF")); + } + + @Test + public void literalAndRandom() { + assertEquals("113.96.181.18", IzXffHeader.resolve("113.96.181.18")); + String ip = IzXffHeader.resolve("random"); + assertTrue(ip, ip.matches("\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}")); + } + + @Test + public void applyRemovesWhenOff() { + MultiMap h = MultiMap.caseInsensitiveMultiMap().set("X-Forwarded-For", "1.1.1.1"); + System.clearProperty(IzXffHeader.PROP); + if (System.getenv(IzXffHeader.ENV) == null) { + IzXffHeader.apply(h); + assertFalse(h.contains("X-Forwarded-For")); + } + System.setProperty(IzXffHeader.PROP, "8.8.8.8"); + IzXffHeader.apply(h); + assertEquals("8.8.8.8", h.get("X-Forwarded-For")); + System.clearProperty(IzXffHeader.PROP); + } +} From 6acb774c87f78ab78d0570584dea61e2e6680802 Mon Sep 17 00:00:00 2001 From: qaiu Date: Wed, 14 Oct 2026 04:38:00 +0800 Subject: [PATCH 2/2] release: 0.4.8 Youxiang auth fallback and configurable XFF --- README.md | 2 +- pom.xml | 2 +- web-front/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 037c96d..7900cba 100644 --- a/README.md +++ b/README.md @@ -461,7 +461,7 @@ docker run --rm -v /var/run/docker.sock:/var/run/docker.sock containrrr/watchtow > 注意: netdisk-fast-download.service中的ExecStart的路径改为实际路径 ```shell cd ~ -wget -O netdisk-fast-download.zip https://github.com/qaiu/netdisk-fast-download/releases/download/v0.4.7/netdisk-fast-download-linux-amd64.zip +wget -O netdisk-fast-download.zip https://github.com/qaiu/netdisk-fast-download/releases/download/v0.4.8/netdisk-fast-download-linux-amd64.zip unzip netdisk-fast-download.zip cd netdisk-fast-download bash service-install.sh diff --git a/pom.xml b/pom.xml index 9296821..3c11261 100644 --- a/pom.xml +++ b/pom.xml @@ -17,7 +17,7 @@ - 0.4.7 + 0.4.8 17 17 17 diff --git a/web-front/package.json b/web-front/package.json index 2a24389..8bd38a7 100644 --- a/web-front/package.json +++ b/web-front/package.json @@ -1,6 +1,6 @@ { "name": "nfd-web", - "version": "0.4.7", + "version": "0.4.8", "private": true, "scripts": { "serve": "vue-cli-service serve",