diff --git a/README.md b/README.md
index 0781870..7838eba 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
-
-
+
+
redViewer(rV)

@@ -17,15 +17,17 @@
轻简风格的漫画阅读器。
+> [26/02/18] nyc.mn 旧域名已废弃,新域名后缀 xyz
+
-
-
+
+
-
-
+
+
-
+
diff --git a/backend/api/__init__.py b/backend/api/__init__.py
index 11a1392..9f9dc59 100644
--- a/backend/api/__init__.py
+++ b/backend/api/__init__.py
@@ -14,7 +14,7 @@
from core import lib_mgr
from storage import StorageBackendFactory
from api.routes.comic import index_router
-from api.routes.root import root_router
+from api.routes.root import root_router, api_config_router
from utils.cbz_cache import close_cbz_cache
staticFiles = None
@@ -60,6 +60,7 @@ def register_router(app: FastAPI) -> None:
if kemono_path and kemono_path.exists():
from api.routes.kemono import index_router as kemono_index_router
app.include_router(kemono_index_router, prefix="", tags=['kemono'])
+ app.include_router(api_config_router, prefix="", tags=['api'])
app.include_router(root_router, prefix="", tags=['root'])
diff --git a/backend/api/routes/root.py b/backend/api/routes/root.py
index e80410c..4dc4d25 100644
--- a/backend/api/routes/root.py
+++ b/backend/api/routes/root.py
@@ -3,8 +3,11 @@
"""Root Router - 认证和配置管理 API"""
import time
+import httpx
from functools import wraps
+from urllib.parse import urlsplit
from fastapi import APIRouter, HTTPException, Header
+from fastapi.responses import JSONResponse
from pydantic import BaseModel
from typing import Optional
@@ -12,6 +15,7 @@
from core.crypto import decrypt
root_router = APIRouter(prefix='/root')
+api_config_router = APIRouter(prefix='/api')
# ===== 鉴权相关 =====
@@ -69,6 +73,12 @@ class WhitelistUpdate(BaseModel):
whitelist: list[str]
+class ApiConfigUpdate(BaseModel):
+ backendUrl: str | None = None
+ currentBackend: str | None = None
+ secret: str | None = None
+
+
@root_router.get("/")
async def root_status():
return {"status": "ok", "has_secret": is_auth_required()}
@@ -130,4 +140,43 @@ async def update_whitelist(req: WhitelistUpdate, x_secret: Optional[str] = Heade
if is_auth_required() and not verify_secret(x_secret or ''):
raise HTTPException(401, "鉴权失败")
backend.config.set('root_whitelist', req.whitelist)
- return {"success": True}
\ No newline at end of file
+ return {"success": True}
+
+
+@api_config_router.get('/config')
+async def get_api_config():
+ return {
+ 'backendUrl': backend.config.get('frontend_backend_url'),
+ 'bgGif': None
+ }
+
+
+@api_config_router.post('/config')
+async def update_api_config(req: ApiConfigUpdate):
+ if not req.secret:
+ return JSONResponse({'error': '需要密钥'}, status_code=401)
+ if not is_auth_required():
+ return JSONResponse({'error': '请先设置密钥'}, status_code=403)
+ if not verify_secret(req.secret):
+ return JSONResponse({'error': '密钥验证失败'}, status_code=401)
+
+ target = (req.backendUrl or '').strip().rstrip('/')
+ if not target:
+ return JSONResponse({'error': '需要目标后端地址'}, status_code=400)
+ try:
+ parts = urlsplit(target)
+ except ValueError:
+ return JSONResponse({'error': '地址格式不正确'}, status_code=400)
+ if parts.scheme not in ('http', 'https') or not parts.netloc:
+ return JSONResponse({'error': '地址必须以 http:// 或 https:// 开头'}, status_code=400)
+
+ try:
+ async with httpx.AsyncClient(timeout=5.0) as client:
+ r = await client.get(f'{target}/root/')
+ if r.status_code >= 400:
+ return JSONResponse({'error': '无法连接目标后端'}, status_code=502)
+ except httpx.HTTPError:
+ return JSONResponse({'error': '无法连接目标后端'}, status_code=502)
+
+ backend.config.set('frontend_backend_url', target)
+ return {'success': True}
diff --git a/deploy/tauri/Cargo.toml b/deploy/tauri/Cargo.toml
index b05acca..51a131d 100644
--- a/deploy/tauri/Cargo.toml
+++ b/deploy/tauri/Cargo.toml
@@ -35,7 +35,7 @@ toml = "0.8"
parking_lot = "0.12"
# Tauri dependencies (src-tauri only)
-tauri = { version = "2.9.5", features = ["tray-icon"] }
+tauri = { version = "2.9.5", features = ["tray-icon", "macos-private-api"] }
tauri-plugin-opener = "2"
tauri-plugin-single-instance = "2"
notify-rust = "4"
diff --git a/deploy/tauri/lib/src/paths.rs b/deploy/tauri/lib/src/paths.rs
index 6fd4e7f..2a26c26 100644
--- a/deploy/tauri/lib/src/paths.rs
+++ b/deploy/tauri/lib/src/paths.rs
@@ -43,12 +43,9 @@ pub fn resolve_uv() -> anyhow::Result
{
#[cfg(target_os = "macos")]
{
- // On macOS, uv is bundled in Contents/Resources alongside other resources
- let uv_path = exe_dir
- .parent() // Contents
- .map(|p| p.join("Resources").join("uv"))
- .ok_or_else(|| anyhow::anyhow!("cannot resolve macOS resources path"))?;
- return Ok(uv_path);
+ // externalBin 打包后位于 Contents/MacOS/ 目录(与主程序同目录)
+ // 见: https://v2.tauri.app/distribute/macos-application-bundle
+ Ok(exe_dir.join("uv"))
}
#[cfg(target_os = "linux")]
diff --git a/deploy/tauri/src-tauri/Cargo.toml b/deploy/tauri/src-tauri/Cargo.toml
index c44d2f9..83858e6 100644
--- a/deploy/tauri/src-tauri/Cargo.toml
+++ b/deploy/tauri/src-tauri/Cargo.toml
@@ -15,7 +15,7 @@ tauri-build = { workspace = true }
[dependencies]
rv_lib = { path = "../lib", package = "lib" }
-tauri = { workspace = true }
+tauri = { workspace = true, features = ["tray-icon", "macos-private-api"] }
tauri-plugin-opener = { workspace = true }
tauri-plugin-single-instance = { workspace = true }
notify-rust = { workspace = true }
diff --git a/deploy/tauri/src-tauri/tauri.conf.json b/deploy/tauri/src-tauri/tauri.conf.json
index 6e7e66c..a5f925e 100644
--- a/deploy/tauri/src-tauri/tauri.conf.json
+++ b/deploy/tauri/src-tauri/tauri.conf.json
@@ -10,6 +10,7 @@
"frontendDist": "../dist"
},
"app": {
+ "macOSPrivateApi": true,
"windows": [],
"security": {
"csp": null
diff --git a/deploy/tauri/src-tauri/windows/hooks.nsh b/deploy/tauri/src-tauri/windows/hooks.nsh
index 54a8362..850c705 100644
--- a/deploy/tauri/src-tauri/windows/hooks.nsh
+++ b/deploy/tauri/src-tauri/windows/hooks.nsh
@@ -197,6 +197,10 @@ FunctionEnd
; Handles config saving and dependency installation
;------------------------------------------------------------------------------
!macro NSIS_HOOK_POSTINSTALL
+ ; Add firewall rules for ports 8080 and 12345
+ DetailPrint "Adding firewall rules..."
+ nsExec::ExecToLog 'netsh advfirewall firewall add rule name="rV" dir=in action=allow protocol=TCP localport=8080,12345'
+
; Create config directory
CreateDirectory "${CONFIG_DIR}"
@@ -265,6 +269,9 @@ FunctionEnd
; POSTUNINSTALL Hook
;------------------------------------------------------------------------------
!macro NSIS_HOOK_POSTUNINSTALL
+ ; Remove firewall rule
+ nsExec::ExecToLog 'netsh advfirewall firewall delete rule name="rV"'
+
; Clean up runtime-generated files only on full uninstall (not upgrade)
${If} $UpdateMode <> 1
Delete /REBOOTOK "$INSTDIR\res\src\uv.lock"
diff --git a/docs/.vitepress/theme/MyLayout.vue b/docs/.vitepress/theme/MyLayout.vue
index e5c8500..bc6099c 100644
--- a/docs/.vitepress/theme/MyLayout.vue
+++ b/docs/.vitepress/theme/MyLayout.vue
@@ -7,7 +7,7 @@ const { Layout } = DefaultTheme
diff --git a/docs/_github/preset.md b/docs/_github/preset.md
index 955b96b..0777a20 100644
--- a/docs/_github/preset.md
+++ b/docs/_github/preset.md
@@ -1,4 +1,4 @@
---
-[🚀快速开始](https://doc.redviewer.nyc.mn/deploy/) | [❓常见问题](https://doc.redviewer.nyc.mn/faq/)
+[🚀快速开始](https://rv.101114105.xyz/deploy/) | [❓常见问题](https://rv.101114105.xyz/faq/)
diff --git a/docs/_github/release_notes.md b/docs/_github/release_notes.md
index 5a99644..52abff6 100644
--- a/docs/_github/release_notes.md
+++ b/docs/_github/release_notes.md
@@ -1,4 +1,6 @@
## 🍢 Feat/Fix
-✨ 桌面应用,当前win(mac/linux很快就有
++ nyc.mn 旧域名已废弃,新域名后缀 xyz
++ win安装自动开防火墙
++ 文档更新内容,例如个人更方便的 Tunnel 方案
diff --git a/docs/contribute/feed.md b/docs/contribute/feed.md
index 31296cc..175e87e 100644
--- a/docs/contribute/feed.md
+++ b/docs/contribute/feed.md
@@ -18,8 +18,8 @@
- 【Linux.do】给 CGS 和 rv 点 star ,
(注册不到半年的gh号不受理)
- 然后加群备注 lxd注册-{github用户名},
阅读 lxd 注册群公告后根据指示操作
+ 【Linux.do】
要求有30star以上的repo
或一年50contributions,
没达标的请回
+ 加群时备注一下,然后私我即可
diff --git a/docs/deploy/adv.md b/docs/deploy/adv.md
index 2d552ff..46bbba1 100644
--- a/docs/deploy/adv.md
+++ b/docs/deploy/adv.md
@@ -5,25 +5,12 @@

-## 后端
+## 一、统一用 Tunnel 方案
-1. 参考 [一命(令)部署](/deploy/) 的 单独部署/运行`后端`命令 部分
-2. `backend.Dockerfile` 仅为在线体验服务而设,用在本地时请自测
-
-::: info 运行容器/平台
-
-1. 用服务器 和 公网 ip,就这样
-
-> [!warning] 确保你的后端防火墙开放 12345 端口,或已用 nginx 反代,外部自测可访问
-
-2. 市面上的内网穿透 ~~I don't know~~
-:::
-
-::: details 3. 大善人的内网穿透方式(Cloudflare Tunnel)
-
-> [!warning] 必须手上有域名(事前 cf 上设置域),否则用其他部署平台方式
+> 适合个人简单使用
-### 一步到位流程
+**准备一个 cf 账号,已挂 cf 的域名,**
+**已[下载 rv](https://github.com/jasoneri/redViewer/releases) 并安装 并本地局域网已测通**
1. 登录 [Cloudflare Dashboard](https://dash.cloudflare.com/)
2. 打开左侧菜单的 "Zero Trust"
@@ -31,13 +18,29 @@
4. 选择 "Cloudflare" > "起名后保存隧道"
5. 按指示在 pc/后端 安装连接器运行命令,直到下方 Connectors 状态出现 "已连接",点击下一步
-### 收尾(添加已发布应用程序路由)
-
> [!Tip] 只有事前在 cf 设置了域,并成功接通,这步才能选择 域
-6. 添加路由:子域与域自己选择
+6. 添加路由:子域与域自己选择(举例是`backend.bb.cc`)
7. 服务:类型选 `http`,URL 填 `localhost:12345`,点完成设置
+8. 进这个tunnel的配置点`添加已发布应用程序路由`,仿照第6,7步,填另一个子域名(举例是`frontend.bb.cc`),对照`localhost:8080`
+9. 开了 rv 的 pc 浏览器进`localhost:8080`,进入超管,将`后端配置`的地址改为`http://backend.bb.cc`,点保存并刷新
+10. 手机进`frontend.bb.cc`测试一下
+11. 可选,在域名左侧栏安全性增加安全规则,把非 CN 的 IP 全部禁掉
+
+## 二、前后端分离
+
+> 本地直接用安装包的话可跳过后端
+
+### 后端
+
+1. 参考 [一命(令)部署](/deploy/) 的 单独部署/运行`后端`命令 部分
+2. `backend.Dockerfile` 仅为在线体验服务而设,用在本地时请自测
+
+::: info 运行容器/平台
+1. 用服务器 和 公网 ip,就这样
+
+> [!warning] 确保你的后端防火墙开放 12345 端口,或已用 nginx 反代,外部自测可访问
:::
::: details 有关 `rV在线体验` 的部署
@@ -45,18 +48,18 @@
不建议日常使用,所以静态文件托管部分估摸不会扩展开发
:::
-## 前端
+### 前端
-### 🎿 Step-1:Fork 项目
+#### 🎿 Step-1:Fork 项目
[](https://github.com/jasoneri/redViewer/fork)
1. ☝️ 点上面图标进行Fork
2. 点击 `Create fork` 按钮
-### 🏗️ Step-2:创建 Pages 项目
+#### 🏗️ Step-2:创建 Pages 项目
-#### 2.1 访问 Cloudflare Dashboard
+##### 2.1 访问 Cloudflare Dashboard
[](https://dash.cloudflare.com/?to=/:account/pages/new/provider/github)
@@ -65,7 +68,7 @@
这种的返回到 github 上),access 权限增加 redViewer 或 All
3. 返回 cf 选 redViewer 点击 "开始设置"
-#### 2.2 配置项目设置
+##### 2.2 配置项目设置
| 配置项 | 值 | 说明 |
| -------- | ---- | ---- |
@@ -86,19 +89,19 @@
点击 **"保存并部署"**,等待构建完成,如无意外可以验证去耍了
-### 🗄️ Step-3:配置 KV 存储
+#### 🗄️ Step-3:配置 KV 存储
::: warning 如需通过 `超管` 窗口切换后端 url 的话,"KV 命名空间"是必须配置的
**全局生效**:后端地址保存到 KV 后,所有用户(包括游客)刷新页面即可生效。
:::
-#### 3.1 创建 KV 命名空间
+##### 3.1 创建 KV 命名空间
1. 选择左侧菜单的 "储存和数据库" > "Workers KV"
2. 点击"新建实例"按钮
3. 名称填写:`RV_KV` 进行创建
-#### 3.2 绑定 KV 到 Pages 项目
+##### 3.2 绑定 KV 到 Pages 项目
1. 返回上面创建的 Pages > 设置 > 绑定
2. 点击 "添加" > "KV 命名空间"
@@ -106,7 +109,7 @@
4. 选择刚创建的命名空间
5. 点击"保存"
-#### 3.3 重试部署
+##### 3.3 重试部署
1. 进入项目的 "部署" 页面
2. 找到最新的部署记录
diff --git a/docs/guide/index.md b/docs/guide/index.md
index 6ef22e9..230c778 100644
--- a/docs/guide/index.md
+++ b/docs/guide/index.md
@@ -1,6 +1,6 @@
# 🎸功能详细预览
-建议新窗口开 [](https://demo.redviewer.nyc.mn/) 边看此文档,直观功能演示
+建议新窗口开 [](https://demo-rv.101114105.xyz/) 边看此文档,直观功能演示
## 📚 列表/网格预览
@@ -18,6 +18,11 @@
## 🎲 其他说明
+### 未提及
+
++ 章节页预览 > 点一下系列名,弹出菜单系列列表可跳转
++ 阅读 > 翻页模式点一下下方页数可跳转页首页尾
+
### 筛选相关
筛选状态下,按`重新加载`就能恢复原始列表。
diff --git a/frontend/src/components/func/PageReader.vue b/frontend/src/components/func/PageReader.vue
index bd68914..af40573 100644
--- a/frontend/src/components/func/PageReader.vue
+++ b/frontend/src/components/func/PageReader.vue
@@ -11,7 +11,29 @@
:src="currentUrl"
fit="contain"
/>
-
{{ currentPage + 1 }} / {{ props.imgUrls.length }}
+
+
+
+
+ {{ currentPage + 1 }} / {{ props.imgUrls.length }}
+
+
+
+
@@ -35,6 +57,7 @@