-
Notifications
You must be signed in to change notification settings - Fork 0
Architecture
Language / 語言 / 语言: English · 繁體中文 · 简体中文
flowchart TB
subgraph Desktop["Desktop app (Tauri v2, Rust shell)"]
UI["Frontend<br/>Svelte 5 + TypeScript + Tailwind v4"]
Rust["Rust IPC layer<br/>(main.rs)"]
end
Engine["Python engine sidecar<br/>engine_sidecar.py"]
YTDLP["yt-dlp"]
FFMPEG["ffmpeg (bundled, GPLv3)"]
AI["AI Orchestrator<br/>(OpenRouter, multi-model)"]
UI -- "Tauri commands" --> Rust
Rust -- "spawns per operation<br/>stdio newline-JSON" --> Engine
Engine --> YTDLP
Engine --> FFMPEG
UI -. "optional, user-confirmed" .-> AI
AI -- "plan --> execute via" --> Rust
-
Frontend: Svelte 5 + TypeScript + Tailwind CSS v4. Talks to the backend only through a small
api.tsabstraction — aTauriApiimplementation (real IPC) and aMockApiimplementation (browser fallback with fake data, used when there's no Tauri host — e.g. during frontend-only dev). -
Rust shell (Tauri v2): owns the window, native menus, and file dialogs; exposes a handful of
#[tauri::command]functions the frontend calls. It does not implement any download/convert logic itself — it spawns the Python engine as a subprocess per operation and pipes JSON messages over stdio. - Python engine sidecar: a single well-defined newline-delimited JSON-RPC protocol. One process is spawned per operation (a download, a batch convert, etc.) rather than one long-lived daemon — simpler lifecycle, no persistent state to corrupt, and a crash only kills one operation instead of the whole engine.
- yt-dlp: does the actual site-specific extraction/downloading.
- ffmpeg: bundled alongside the packaged app for format conversion and remuxing; invoked as a subprocess, not linked into the binary — see FAQ for why that matters for licensing.
- AI Orchestrator (optional, off by default until you add an API key): a small pipeline of separate OpenRouter models — PLANNER drafts a plan, EXECUTOR turns it into concrete engine calls, a deterministic (non-AI) safety guard checks the calls against an allowlist, CHECKER reviews the result, and only after you click Confirm does anything touch the filesystem. A SUMMARIZER explains what happened afterward. No step in this pipeline can execute a file operation before your explicit confirmation.
This repo holds every major version as an independent, self-contained branch (Version3.0, Version4.0, ...) rather than folders in one branch. V3.0 (pure Python: tkinter GUI + Flask web app) and V4.0 (Tauri + Svelte + Python sidecar) don't share code or architecture, so forcing them into one history would just add merge noise with no benefit. Each V4.x patch release overwrites the Version4.0 branch in place; a new architecture line only gets its own branch at the next major version (Version5.0).
All user-facing strings live in locales/{en,zh_tw,zh_cn}.json (165 keys each) and are loaded by both the Python engine (for log/error messages) and the Svelte frontend, with a fallback chain: requested language → English → raw key (so a missing translation never crashes the UI, it just shows the key).
packaging/engine_sidecar.spec builds the Python engine with PyInstaller in onedir mode (not onefile) — onefile's self-extracting startup cost is paid on every spawn, which matters here since a fresh sidecar process starts per operation. packaging/build-desktop.ps1 orchestrates the full build: PyInstaller → copy ffmpeg alongside it → tauri build, producing an NSIS .exe and an MSI, both with the engine and ffmpeg bundled inside (no separate install steps for the end user).
flowchart TB
subgraph Desktop["桌面 App(Tauri v2,Rust 外殼)"]
UI["前端<br/>Svelte 5 + TypeScript + Tailwind v4"]
Rust["Rust IPC 層<br/>(main.rs)"]
end
Engine["Python 引擎 sidecar<br/>engine_sidecar.py"]
YTDLP["yt-dlp"]
FFMPEG["ffmpeg(內建,GPLv3)"]
AI["AI 協調器<br/>(OpenRouter,多模型)"]
UI -- "Tauri commands" --> Rust
Rust -- "每次操作各自產生<br/>stdio 換行 JSON" --> Engine
Engine --> YTDLP
Engine --> FFMPEG
UI -. "選用,需使用者確認" .-> AI
AI -- "產生計畫 --> 透過此執行" --> Rust
-
前端:Svelte 5 + TypeScript + Tailwind CSS v4。僅透過小型
api.ts抽象層與後端溝通——TauriApi(真正 IPC)與MockApi(無 Tauri 主機時的瀏覽器備援,用假資料,例如純前端開發時)。 -
Rust 外殼(Tauri v2):負責視窗、原生選單、檔案對話框;提供少量
#[tauri::command]函式給前端呼叫。本身不實作任何下載/轉換邏輯——每次操作都會產生一個 Python 引擎子行程,透過 stdio 傳遞 JSON 訊息。 - Python 引擎 sidecar:單一明確定義的換行分隔 JSON-RPC 協定。每次操作(一次下載、一次批次轉換等)都產生一個新行程,而非單一長駐 daemon——生命週期較簡單、沒有需要擔心的持久狀態,且一次當機只影響一個操作,不會拖垮整個引擎。
- yt-dlp:實際負責各網站的特定擷取/下載邏輯。
- ffmpeg:與封裝好的 app 一起內建,用於格式轉換與重新封裝;以子行程方式呼叫,並未連結進執行檔本身——授權相關原因見 FAQ。
- AI 協調器(選用,預設關閉,需自行加入 API Key):由多個獨立 OpenRouter 模型組成的小型流水線——PLANNER 起草計畫、EXECUTOR 轉成具體引擎呼叫、一個確定性(非 AI)安全守門機制依白名單檢查呼叫內容、CHECKER 審查結果,唯有你按下「確認」後才會真正動到檔案系統。事後由 SUMMARIZER 說明發生了什麼。此流水線中沒有任何一步能在你明確確認前執行檔案操作。
這個 repo 把每個主要版本各自放在獨立、自成一體的 branch(Version3.0、Version4.0……),而非放在同一 branch 底下的資料夾。V3.0(純 Python:tkinter GUI + Flask 網頁版)與 V4.0(Tauri + Svelte + Python sidecar)並不共用程式碼或架構,硬把兩者塞進同一條歷史只會徒增合併雜訊、沒有實質好處。每個 V4.x 的更新版本會直接覆蓋 Version4.0 branch;只有到下一個主要版本(Version5.0)架構真正改變時,才會開新的 branch。
所有面向使用者的字串都放在 locales/{en,zh_tw,zh_cn}.json(各 165 個 key),由 Python 引擎(日誌/錯誤訊息)與 Svelte 前端共同載入,並有備援鏈:請求語言 → 英文 → 原始 key(缺少翻譯時不會讓 UI 當掉,只會顯示 key 本身)。
packaging/engine_sidecar.spec 以 PyInstaller onedir 模式(非 onefile)建置 Python 引擎——onefile 每次啟動都要付出自解壓縮的成本,而這裡每次操作都會啟動一個新的 sidecar 行程,因此格外在意這點。packaging/build-desktop.ps1 統籌整個建置流程:PyInstaller → 把 ffmpeg 複製到旁邊 → tauri build,產出 NSIS .exe 與 MSI,兩者都已內建引擎與 ffmpeg(終端使用者不需要另外安裝任何東西)。
flowchart TB
subgraph Desktop["桌面 App(Tauri v2,Rust 外壳)"]
UI["前端<br/>Svelte 5 + TypeScript + Tailwind v4"]
Rust["Rust IPC 层<br/>(main.rs)"]
end
Engine["Python 引擎 sidecar<br/>engine_sidecar.py"]
YTDLP["yt-dlp"]
FFMPEG["ffmpeg(内置,GPLv3)"]
AI["AI 协调器<br/>(OpenRouter,多模型)"]
UI -- "Tauri commands" --> Rust
Rust -- "每次操作各自生成<br/>stdio 换行 JSON" --> Engine
Engine --> YTDLP
Engine --> FFMPEG
UI -. "可选,需用户确认" .-> AI
AI -- "生成计划 --> 通过此执行" --> Rust
-
前端:Svelte 5 + TypeScript + Tailwind CSS v4。仅通过小型
api.ts抽象层与后端通信——TauriApi(真正 IPC)与MockApi(无 Tauri 主机时的浏览器备用方案,用假数据,例如纯前端开发时)。 -
Rust 外壳(Tauri v2):负责窗口、原生菜单、文件对话框;提供少量
#[tauri::command]函数给前端调用。本身不实现任何下载/转换逻辑——每次操作都会生成一个 Python 引擎子进程,通过 stdio 传递 JSON 消息。 - Python 引擎 sidecar:单一明确定义的换行分隔 JSON-RPC 协议。每次操作(一次下载、一次批量转换等)都生成一个新进程,而非单一长驻 daemon——生命周期更简单、没有需要担心的持久状态,且一次崩溃只影响一个操作,不会拖垮整个引擎。
- yt-dlp:实际负责各网站的特定提取/下载逻辑。
- ffmpeg:与打包好的 app 一起内置,用于格式转换与重新封装;以子进程方式调用,并未链接进可执行文件本身——许可证相关原因见 FAQ。
- AI 协调器(可选,默认关闭,需自行添加 API Key):由多个独立 OpenRouter 模型组成的小型流水线——PLANNER 起草计划、EXECUTOR 转成具体引擎调用、一个确定性(非 AI)安全守门机制依白名单检查调用内容、CHECKER 审查结果,只有你点击「确认」后才会真正动到文件系统。事后由 SUMMARIZER 说明发生了什么。此流水线中没有任何一步能在你明确确认前执行文件操作。
这个 repo 把每个主要版本各自放在独立、自成一体的分支(Version3.0、Version4.0……),而非放在同一分支下的文件夹。V3.0(纯 Python:tkinter GUI + Flask 网页版)与 V4.0(Tauri + Svelte + Python sidecar)并不共用代码或架构,硬把两者塞进同一条历史只会徒增合并噪音、没有实质好处。每个 V4.x 的更新版本会直接覆盖 Version4.0 分支;只有到下一个主要版本(Version5.0)架构真正改变时,才会开新分支。
所有面向用户的字符串都放在 locales/{en,zh_tw,zh_cn}.json(各 165 个 key),由 Python 引擎(日志/错误消息)与 Svelte 前端共同加载,并有回退链:请求语言 → 英文 → 原始 key(缺少翻译时不会让 UI 崩溃,只会显示 key 本身)。
packaging/engine_sidecar.spec 以 PyInstaller onedir 模式(非 onefile)构建 Python 引擎——onefile 每次启动都要付出自解压的成本,而这里每次操作都会启动一个新的 sidecar 进程,因此格外在意这点。packaging/build-desktop.ps1 统筹整个构建流程:PyInstaller → 把 ffmpeg 复制到旁边 → tauri build,产出 NSIS .exe 与 MSI,两者都已内置引擎与 ffmpeg(终端用户不需要另外安装任何东西)。