-
Notifications
You must be signed in to change notification settings - Fork 0
WebUI Frontend
WebUI 是一个 Vanilla JavaScript 单页应用(SPA),使用 Vite 8.x 构建。无框架(React/Vue/Angular),采用模块化架构,基于 hash 的路由器、共享状态模块、内联 SVG 图标系统和直接 DOM 操作。
src/webui/
├── index.html # SPA 入口(zh-CN)
├── main.js # 引导
├── vite.config.js # Vite 构建配置
├── package.json # 依赖(vite ^8.1.3)
├── styles/main.css # 双主题 CSS 变量
├── modules/
│ ├── core/ # 核心基础设施
│ │ ├── api.js # API 封装(含鉴权)
│ │ ├── router.js # 基于 hash 的 SPA 路由器
│ │ ├── state.js # 单例状态模块
│ │ ├── theme.js # MD3/Fluent2 双主题引擎
│ │ ├── utils.js # 工具函数
│ │ ├── icons.js # 内联 SVG 图标
│ │ └── wallpaper.js # 水墨晕染遮罩效果
│ ├── pages/ # 页面渲染器
│ │ ├── dashboard.js # 仪表盘
│ │ ├── area.js # A/B/C 区浏览
│ │ ├── config.js # 配置页
│ │ ├── login.js # 登录页
│ │ ├── logs.js # 日志页(TMDB 操作日志 + 主程序日志双来源)
│ │ ├── openlist.js # OpenList 配置
│ │ └── tmdb.js # TMDB 待看列表
│ └── components/ # 可复用组件
│ ├── dialog.js # 模态对话框
│ └── toast.js # 提示通知
└── public/ # 静态资源
- 根目录:
src/webui/,基础路径:./(相对路径) - 输出目录:
../../dist(项目根目录的dist/) - Rollup
manualChunks:core块(modules/core/* + modules/components/*),各页面独立块
cd src/webui
npx vite build # 生产构建 → ../../dist/
npx vite # 开发服务器(HMR)注意:修改 modules/ 下文件后必须重新构建,浏览器加载的是 dist/ 的编译文件,不是源文件。
main.js 是前端引导入口,在 DOMContentLoaded 中完成初始化。其中鉴权与路由的启动顺序为:先 fetch('/api/admin/status') 获取管理员密码是否已设置(setHasPassword(d.has_password)),再在该请求的 .finally 回调中绑定 hashchange 事件并首次调用 router()。这样可确保密码状态就绪后再激活路由的 auth guard,避免竞争条件。
此外,main.js 静态导入 openlist.js(import { _checkApiStatus } from './modules/pages/openlist.js'),因此 openlist.js 不属于路由懒加载的页面模块,而是随入口一同加载,用于页面渲染后的 API 状态检测。
- 支持超时(默认 10s,
AbortController) - 自动附加
X-Session-Token头 - 401 时清除 token、跳转到
#login、抛出ApiAuthError
- 基于 hash 的路由,含鉴权守卫
- 渲染过时检测(
_renderGen计数器) - 动态导入页面模块:
await import('../pages/xxx.js')
路由表:
| Hash | 页面模块 | 渲染函数 |
|---|---|---|
#login |
login.js |
renderLogin |
#dashboard |
dashboard.js |
renderDashboard |
#area_* |
area.js |
renderArea(el, area, params) |
#tmdb |
tmdb.js |
renderTmdb(el, params) |
#logs |
logs.js |
renderLogs(TMDB 操作日志 /api/tmdb/logs + 主程序日志 /api/logs 双来源,Tab 切换) |
#config |
config.js |
renderConfig(el, params) |
-
CONFIG常量(轮询间隔、分页大小、缓存限制) -
OpenListState— 引擎状态、API 状态 - 鉴权状态 —
_hasPassword(null = 未初始化) - TMDB 状态 — 待看列表缓存(30 分钟 TTL)、类型缓存(1000 LRU)
- UI 配置 — 带
AbortController取消进行中的保存
-
syncTheme()— 应用data-system、data-color、data-font到<html>,持久化到 localStorage - 两个主题:Material Design 3(
data-system="material")和 Fluent 2(data-system="fluent") - 四种颜色:
blue、purple、green、orange - 三种字号:
lg(15px)、sm(13px)、xs(11px)
Canvas 水墨鼠标擦除效果(destination-out 合成模式)。5 种笔刷变体,1800ms 生命周期,最多 160 个印记,320px 笔刷尺寸。触屏设备跳过效果。
注意:以下两项均为后端函数,不属于前端代码。
-
PBKDF2-HMAC-SHA256 密码哈希(600,000 次迭代)—
_hash_password()为后端server.py中WebUIServer的方法(routes.py另有等价的_hash_password_pbkdf2()供配置写入场景使用,前端不直接调用)。 -
IP 白名单(仅局域网)—
_is_lan_ip()为后端routes.py中定义的工具函数,server.py导入并复用,前端不涉及。
免 Token 路径:/api/config、/api/webui/config/ui、/api/tmdb/avatar、/api/tmdb/poster、/api/openlist/status、/api/openlist/ping、/api/admin/status、/api/login、静态资源
首次使用以分步卡片形式引导,一张卡片含 7 步行,覆盖以下引导步骤:
-
password— 确认管理员密码 -
tmdb— 配置 TMDB -
openlist— 配置 OpenList -
main— 启动主程序 -
view_ab— 浏览 A/B 区 -
tmdb_refresh— 刷新 TMDB 待看列表 -
tmdb_match— 检测 TMDB 收录状态
状态读取:引导状态不通过独立 status 接口,而是由前端通过 GET /api/config/status 读取(其响应包含 onboarding_completed 等键,驱动引导卡片展示);GET /api/webui/config/ui(免 Token)用于读取/写入 UI 配置。关键键位包括 onboarding_completed、view_ab_completed、tmdb_refresh_completed、tmdb_match_completed(后三者由后端聚合为 *_completed 字段响应;底层存储键为 onboarding_view_ab_completed 等,前缀 onboarding_)。前端据此决定显示哪些卡片及是否弹出引导。
步骤完成调用:单步完成时调用 POST /api/onboarding/complete-step,body 为 {"step": "view_ab"} 等形式(step 仅允许 view_ab / tmdb_refresh / tmdb_match,其它值返回 400)。整体完成或跳过共用 onboarding_completed 配置键,通过 POST /api/webui/config/ui 写入(如 {"onboarding_completed": "1"})。
注意:
onboarding_skipped虽仍保留在后端_UI_CONFIG_ALLOWED_KEYS白名单中,但当前代码无任何位置写入或读取该键,属死键。跳过引导同样写入的是onboarding_completed,并非独立的onboarding_skipped。
注意:不存在
GET /api/onboarding/status端点,文档不做虚构。
区域浏览由 modules/pages/area.js(renderArea(el, area, params))负责,对应后端 GET /api/area/{area}。核心特性:
-
分类 Tab:前端提供「番剧 / 电影 / 全部」等分类 Tab,通过
kind参数切换(anime/movie/other/all)。kind=all即「全部分类」Tab,不做类型筛选但后端仍返回各分类真实计数kind_counts。后端分类由webdav_path路径推断(番剧 / 电影 / 其他)。 -
搜索:区域搜索框传入
q参数,后端走 FTS5 全文搜索(经_escape_fts5_query转义,支持中文),FTS5 失败时回退LIKE子串匹配。 -
空状态提示:当
q为空或搜索无结果时展示空搜索状态提示,引导用户输入关键词。
🏡 返回 Wiki 首页 • 💻 项目源码仓库 • 🐛 提交 Bug / 建议 • 📦 下载最新版本
🚨 安全与自保黄金法则(每页必读)
- 严禁随意重置 OpenList 令牌:播放签名(
?sign=)强依赖服务端密钥。一旦重置,B区所有.strm将瞬间失效报无权播放,只能清库重来!- 调试阶段切勿使用 DELETE:
DELETE会物理删除云端文件,极其危险!建议终身配置为action = "MOVE"(云端一比一树状回收站模式)。- 放心刮削,资产安全:空文件夹清理算法采用严格的零物理文件判定,含有海报图片、
.nfo、外部字幕的目录绝对不会被误删。
本项目遵循 MIT 开源协议。数据无价,请在充分测试后接入生产环境。