| title | SubLens 开发者指南 |
|---|
| 依赖 | 版本 | 安装 |
|---|---|---|
| Node.js | 18+ | nvm install 18 |
| pnpm | 8+ | npm i -g pnpm |
| Rust | 1.70+ | rustup install stable |
| FFmpeg | 最新 | apt install ffmpeg 或 brew install ffmpeg |
| Tesseract | 最新 | apt install tesseract-ocr 或 brew install tesseract |
git clone https://github.com/Agions/SubLens.git
cd SubLens
pnpm install# 前端热重载开发(Rust 后端自动编译)
pnpm tauri dev
# 仅前端开发(mock Tauri 调用)
pnpm vite
# 生产构建
pnpm tauri build
# 前端类型检查
pnpm vue-tsc --noEmit
# ESLint
pnpm lint
# 测试
pnpm test# 查看 Rust 版本
rustc --version # 需要 1.70+
# 检查 Tauri CLI
cargo tauri --version
# Rustfmt 格式化
cargo fmt
# Rust Lint
cargo clippy -- -D warningsSubLens/
├── src/ # Vue 前端
│ ├── components/ # UI 组件
│ ├── composables/ # 组合式函数
│ ├── stores/ # Pinia store
│ └── core/ # 纯业务逻辑(可独立测试)
│
├── src-tauri/ # Rust 后端
│ ├── src/
│ │ ├── main.rs # 入口,调用 lib::run()
│ │ ├── lib.rs # Tauri Builder 配置 + 命令注册
│ │ └── commands/ # IPC 命令
│ │ ├── mod.rs
│ │ ├── video.rs # get_video_metadata, extract_frame_at_time
│ │ ├── export.rs # 9 格式字幕导出
│ │ ├── scene.rs # 场景检测
│ │ ├── file.rs # 文件对话框
│ │ ├── system.rs # 系统依赖检查
│ │ ├── utils.rs # 工具函数
│ │ └── types.rs # 共享类型
│ └── tauri.conf.json # Tauri 配置
│
└── docs/ # Docsify 在线文档
├── README.md # 封面(Docsify 自动读取)
├── _sidebar.md # 侧边导航
├── index.html # Docsify 入口
├── architecture.md
├── developer-guide.md
└── changelog.md
在 src-tauri/src/commands/ 下新建文件,例如 hello.rs:
//! Hello world command module.
#[tauri::command]
pub async fn greet(name: String) -> String {
format!("Hello, {}!", name)
}在 commands/mod.rs 添加:
pub mod hello;在 src-tauri/src/lib.rs 添加公开导出:
pub use commands::hello::greet;并在 generate_handler! 中注册:
invoke_handler(tauri::generate_handler![
// ... existing commands ...
commands::hello::greet,
])import { invoke } from '@tauri-apps/api/core'
const greeting = await invoke<string>('greet', { name: 'SubLens' })import { Pipeline, DEFAULT_PIPELINE_OPTIONS } from '@/core/Pipeline'
const pipeline = new Pipeline({
jitterMinDuration: 0.5, // 调高:过滤更多噪声
splitSimilarityThreshold: 0.9, // 调高:更少合并
})
const cleaned = pipeline.process(rawSubtitles)
// 单独运行某阶段(调试)
const afterDenoise = pipeline.processStage(rawSubtitles, 1)- 在
src-tauri/src/commands/types.rs的ExportFormat枚举添加变体:
pub enum ExportFormat {
SRT,
WebVTT,
ASS,
SSA,
JSON,
TXT,
LRC, // 新增 LRC 格式
SBV,
CSV,
}- 在
src-tauri/src/commands/export_fmt.rs添加导出函数:
pub fn export_as_lrc(subtitles: &[SubtitleItem]) -> String {
subtitles.iter()
.map(|sub| {
let start = format_timestamp_lrc(sub.start_time);
format!("[{}] {}", start, sub.text)
})
.collect::<Vec<_>>()
.join("\n")
}- 在
src-tauri/src/commands/export.rs的export_subtitlesmatch 中添加分支:
ExportFormat::LRC => export_as_lrc(&subtitles),- 前端 TypeScript
ExportFormat类型定义同步更新。
# 启用 tracing 日志(开发模式)
RUST_LOG=debug pnpm tauri dev# Vite 开发服务器(端口 5173)
pnpm vite
# Chrome DevTools: F12 → Sources → 找到对应 .ts 文件打断点// 在前端添加日志包装
import { invoke } from '@tauri-apps/api/core'
async function invokeDebug<T>(cmd: string, args: Record<string, unknown>) {
console.log(`[Tauri] invoking ${cmd}`, args)
const result = await invoke<T>(cmd, args)
console.log(`[Tauri] ${cmd} =>`, result)
return result
}# 手动测试帧提取
ffmpeg -ss 10.5 -i input.mp4 -vframes 1 output.png
# 检查视频元数据
ffprobe -v quiet -print_format json -show_format -show_streams input.mp4pnpm test # 运行所有测试
pnpm test -- --watch # Watch 模式
pnpm test src/core/Pipeline.ts # 测试特定文件cargo test --manifest-path src-tauri/Cargo.toml# 手动验证导出文件
cargo test --manifest-path src-tauri/Cargo.tomlpnpm tauri build产物位于 src-tauri/target/release/bundle/:
- macOS:
.app/.dmg - Linux:
.AppImage/.deb - Windows:
.exe/.msi
版本在 package.json 和 src-tauri/Cargo.toml 中必须保持同步:
# package.json
"version": "3.6.0"
# src-tauri/Cargo.toml
version = "3.6.0"发布流程:更新版本 → git tag → GitHub Actions 自动构建 → Draft Release。详细 Release 工作流见 .github/workflows/release.yml。
.github/workflows/ 下有 3 个 workflow 文件,其中 ci.yml 内含 3 个并行 job:
| Workflow | 触发 | Job | 说明 |
|---|---|---|---|
ci.yml |
PR / push | quality |
vue-tsc + ESLint + Vitest |
ci.yml |
PR / push | build |
Tauri 生产构建 |
ci.yml |
PR / push | rust-test |
cargo test(lib + bins) |
docs.yml |
push (main) | — | VitePress → GitHub Pages |
release.yml |
Git tag | — | Tauri 发布构建 |
本地预览文档(VitePress):
pnpm docs:build # 构建到 docs/.vitepress/dist/
# 或开发模式热重载
pnpm vitepress dev docsA: Tauri 2.x 需要 Rust 1.82+。升级 Rust:
rustup update stable
rustc --version # 确认 >= 1.82A: 检查 Tesseract 是否安装:
tesseract --version如果使用 EasyOCR,确保 node_modules/easyocr 正确安装。
A: 检查 ffmpeg 是否可用:
ffmpeg -version确认视频路径不包含特殊字符(引号、$、反引号)。
A: 确保 scene_detect.py 位于 src-tauri/scripts/ 目录,且 Python 在 PATH 中:
python3 --versionA: 确认命令已在 lib.rs 的 generate_handler! 中注册。
.github/workflows/ 下有 3 个 workflow 文件,其中 ci.yml 内含 3 个并行 job:
| Workflow | 触发 | Job | 说明 |
|---|---|---|---|
ci.yml |
PR / push | quality |
vue-tsc + ESLint + Vitest |
ci.yml |
PR / push | build |
Tauri 生产构建 |
ci.yml |
PR / push | rust-test |
cargo test(lib + bins) |
docs.yml |
push (main) | — | VitePress → GitHub Pages |
release.yml |
Git tag | — | Tauri 发布构建 |
质量门禁标准:
vue-tsc --noEmit必须通过- ESLint
pnpm lint必须通过(允许--fix自动修复) - Vitest 测试套件全部通过
# 质量检查(CI 第一路)
pnpm type-check && pnpm lint
# Rust 检查
cargo clippy -- -D warnings
# 前端测试
pnpm test
# 完整构建
pnpm tauri build详见 architecture.md 完整规范。
| 类型 | 规范 | 示例 |
|---|---|---|
| 模块文件 | snake_case | video_processor.rs |
| 公开函数 | snake_case | get_video_metadata |
| 公开结构体/枚举 | PascalCase | VideoMetadata, ExportFormat |
| 私有函数 | snake_case | extract_frame_ffmpeg |
| 常量 | SCREAMING_SNAKE_CASE | DEFAULT_TIMEOUT_SECS |
| 类型 | 规范 | 示例 |
|---|---|---|
| 组件 | PascalCase | SubtitleList.vue |
| Composables | camelCase + use 前缀 |
useSubtitleList.ts |
| 工具函数 | camelCase | textSimilarity |
| 类型/接口 | PascalCase | PipelineOptions |
| 常量 | SCREAMING_SNAKE_CASE | DEFAULT_PIPELINE_OPTIONS |
SubLens 使用 VitePress 作为文档系统,源码在 docs/ 目录:
docs/
├── .vitepress/
│ └── config.ts # VitePress 配置(导航 + 侧边栏)
├── guide/ # 用户指南(面向使用者)
│ ├── getting-started.md
│ ├── first-extraction.md
│ ├── ocr-engines.md
│ ├── roi.md
│ ├── export-formats.md
│ ├── keyboard-shortcuts.md
│ └── faq.md
├── api/ # API 参考(面向开发者)
│ ├── commands.md # Tauri IPC 命令
│ ├── pipeline.md
│ ├── exporter.md
│ ├── scene-detect.md
│ └── calibrator.md
├── index.md # 文档首页(VitePress Home)
└── architecture.md # 架构设计文档
本地预览文档:
# VitePress dev server(需先安装依赖)
npx vitepress dev docs
# 或
cd docs && npx vitepress dev .- Fork 仓库,创建分支:
git checkout -b feat/my-feature - 遵循本文档的命名规范
- 运行
pnpm type-check确保类型检查通过 - 运行
pnpm lint:fix自动修复格式问题 - Commit 遵循 Conventional Commits:
feat:,fix:,docs:,refactor:,perf: - Push 并提 PR