Technical Documentation: triwinds/ns-emu-tools
ℹ️ Provenance: Multi-Tier Ingestion · CodeWiki Reference
Overview (`readme.md`)
Ns Emu Tools
一个用于安装/更新 NS 模拟器的桌面工具。
项目当前使用 Rust + Tauri 2 构建桌面端,前端使用 Vue 3 + Vite + Vuetify。
技术栈
- 桌面端后端:Rust + Tauri 2(
src-tauri) - 前端:Vue 3 + Vite + Vuetify(
frontend) - 前端构建产物:
web
Features
支持安装 Yuzu EA/正式版模拟器支持 Yuzu 版本检测及更新(yuzu 目前已经停止开发)- 支持安装 Ryubing/Ryujinx 正式/Canary 版模拟器及版本检测及更新
- 支持安装 Eden 模拟器及版本检测及更新
- Eden 下载源已切换到官方自建 Git 仓库
- 支持安装 Citron 模拟器及版本检测及更新(Windows/macOS)
- Citron 下载源使用官方 GitHub Releases
- 自动检测并安装 msvc 运行库
- 支持安装及更新 NS 固件至模拟器
- 支持固件版本检测 (感谢 a709560839 提供的思路)
- 管理模拟器密钥
- Yuzu 金手指管理
- aria2 多线程下载
使用方法
一、使用预构建的版本运行
从 GitHub 发布页(稳定版本) 或
CI 自动构建 下载可执行文件后直接运行即可。
Windows 首次运行时,如系统缺少 WebView2 Runtime,程序会提示下载安装。
二、使用源码运行
cd frontend
bun install
cd ../src-tauri
cargo tauri dev更完整的开发说明参见 开发文档。
讨论组
Telegram: Telegram 讨论组
License
本项目采用 AGPL-3.0 许可证。
Credits
Yuzu - Yuzu 模拟器- Ryubing/Ryujinx - Ryujinx 模拟器
- Eden - Eden 模拟器(官方自建 Git 仓库)
- Citron - Citron 模拟器
hactool - NS 固件解析- nsz - NS 固件解析
- aria2 - aria2 下载器
- bytehaul - Rust 异步 HTTP 下载库
- Github 镜像源 - 来自 X.I.U 大佬的 Github 增强脚本
- pineappleEA - Yuzu EA 版本来源
- THZoria/NX_Firmware - NS 固件来源
- darthsternie.net - NS 固件来源
Overview (`frontend/README.md`)
Vuetify (Default)
This is the official scaffolding tool for Vuetify, designed to give you a head start in building your new Vuetify application. It sets up a base template with all the necessary configurations and standard directory structure, enabling you to begin development without the hassle of setting up the project from scratch.
❗️ Important Links
- 📄 Docs
- 🚨 Issues
- 🏬 Store
- 🎮 Playground
- 💬 Discord
💿 Install
Set up your project using your preferred package manager. Use the corresponding command to install the dependencies:
| Package Manager | Command |
|---|---|
| yarn | yarn install |
| npm | npm install |
| pnpm | pnpm install |
| bun | bun install |
After completing the installation, your environment is ready for Vuetify development.
✨ Features
- 🖼️ Optimized Front-End Stack: Leverage the latest Vue 3 and Vuetify 3 for a modern, reactive UI development experience. Vue 3 | Vuetify 3
- 🗃️ State Management: Integrated with Pinia, the intuitive, modular state management solution for Vue.
- 🚦 Routing and Layouts: Utilizes Vue Router for SPA navigation and vite-plugin-vue-layouts for organizing Vue file layouts. Vue Router | vite-plugin-vue-layouts
- 💻 Enhanced Development Experience: Benefit from TypeScript's static type checking and the ESLint plugin suite for Vue, ensuring code quality and consistency. TypeScript | ESLint Plugin Vue
- ⚡ Next-Gen Tooling: Powered by Vite, experience fast cold starts and instant HMR (Hot Module Replacement). Vite
- 🧩 Automated Component Importing: Streamline your workflow with unplugin-vue-components, automatically importing components as you use them. unplugin-vue-components
- 🛠️ Strongly-Typed Vue: Use vue-tsc for type-checking your Vue components, and enjoy a robust development experience. vue-tsc
These features are curated to provide a seamless development experience from setup to deployment, ensuring that your Vuetify application is both powerful and maintainable.
💡 Usage
This section covers how to start the development server and build your project for production.
Starting the Development Server
To start the development server with hot-reload, run the following command. The server will be accessible at http://localhost:3000:
yarn dev(Repeat for npm, pnpm, and bun with respective commands.)
Add NODE_OPTIONS='--no-warnings' to suppress the JSON import warnings that happen as part of the Vuetify import mapping. If you are on Node v21.3.0 or higher, you can change this to NODE_OPTIONS='--disable-warning=5401'. If you don't mind the warning, you can remove this from your package.json dev script.
Building for Production
To build your project for production, use:
yarn build(Repeat for npm, pnpm, and bun with respective commands.)
Once the build process is completed, your application will be ready for deployment in a production environment.
💪 Support Vuetify Development
This project is built with Vuetify, a UI Library with a comprehensive collection of Vue components. Vuetify is an MIT licensed Open Source project that has been made possible due to the generous contributions by our sponsors and backers. If you are interested in supporting this project, please consider:
- Requesting Enterprise Support
- Sponsoring John on Github
- Sponsoring Kael on Github
- Supporting the team on Open Collective
- Becoming a sponsor on Patreon
- Becoming a subscriber on Tidelift
- Making a one-time donation with Paypal
📑 License
Copyright (c) 2016-present Vuetify, LLC
Overview (`src-tauri/tests/README.md`)
Eden 集成测试
这是 Eden 模拟器的集成测试套件,用于测试获取版本信息和安装功能。
测试概述
可用的测试用例
- test_get_eden_all_versions - 获取所有可用的 Eden 版本
- test_get_eden_release_info - 获取指定版本的详细信息
- test_get_latest_and_install_eden - 完整的集成测试:获取最新版本并安装
- test_install_specific_eden_version - 安装指定版本的 Eden
- test_performance_get_multiple_releases - 性能测试:批量获取版本信息
运行测试
前提条件
- 网络连接 - 所有测试都需要访问 GitHub API
- Aria2 - 下载测试需要 Aria2 支持(安装测试需要)
- 足够的磁盘空间 - 安装测试会下载实际的安装包(约 50-100MB)
运行所有集成测试
由于这些测试需要网络连接和较长时间,默认情况下它们被标记为 #[ignore]。
# 在 src-tauri 目录下
cd src-tauri
# 运行所有被忽略的测试(包括集成测试)
cargo test -- --ignored
# 或者只运行 Eden 集成测试
cargo test --test eden_integration_test -- --ignored
# 显示详细输出(推荐)
cargo test --test eden_integration_test -- --ignored --nocapture运行特定测试
# 只测试获取版本列表(较快)
cargo test test_get_eden_all_versions -- --ignored --nocapture
# 只测试获取版本详情(较快)
cargo test test_get_eden_release_info -- --ignored --nocapture
# 完整安装测试(慢,会下载实际文件)
cargo test test_get_latest_and_install_eden -- --ignored --nocapture
# 性能测试
cargo test test_performance_get_multiple_releases -- --ignored --nocapture调整日志级别
测试使用 tracing 进行日志输出,可以通过环境变量控制日志级别:
# 显示详细日志(debug 级别)
RUST_LOG=debug cargo test --test eden_integration_test -- --ignored --nocapture
# 只显示信息日志(默认)
RUST_LOG=info cargo test --test eden_integration_test -- --ignored --nocapture
# 只显示警告和错误
RUST_LOG=warn cargo test --test eden_integration_test -- --ignored --nocapture测试说明
test_get_eden_all_versions
- 用途: 验证能否成功获取 Eden 的所有可用版本
- 耗时: 约 1-3 秒
- 网络: 需要
- 输出: 版本列表,包含前 5 个版本
test_get_eden_release_info
- 用途: 验证能否获取指定版本的详细信息(包括下载链接等)
- 耗时: 约 1-3 秒
- 网络: 需要
- 输出: 版本详情和资源文件列表
test_get_latest_and_install_eden
- 用途: 完整的集成测试流程
- 获取最新版本
- 下载到临时目录
- 安装到临时目录
- 验证安装结果
- 耗时: 约 1-5 分钟(取决于网络速度)
- 网络: 需要
- 磁盘: 需要临时空间存储下载文件
- 输出: 详细的安装过程和进度
test_install_specific_eden_version
- 用途: 测试安装非最新版本的能力
- 耗时: 约 1-5 分钟
- 网络: 需要
- 输出: 安装过程
test_performance_get_multiple_releases
- 用途: 测试批量获取版本信息的性能
- 耗时: 约 5-10 秒
- 网络: 需要
- 输出: 性能统计信息
注意事项
- 临时文件: 所有测试都使用临时目录,测试结束后会自动清理
- 配置隔离: 测试使用独立的配置,不会影响主程序的配置文件
- 网络容错: 如果网络失败,测试会记录警告而不是直接失败
- Aria2 依赖: 下载测试需要系统中安装了 Aria2
故障排查
测试失败:无法连接到 GitHub
- 检查网络连接
- 检查是否需要配置代理
- GitHub API 可能有速率限制
测试失败:Aria2 错误
- 确认 Aria2 已安装并在 PATH 中
- 检查 Aria2 配置
测试超时
- 网络速度较慢时可能需要更长时间
- 考虑只运行轻量级测试(如版本获取测试)
示例输出
running 1 test
test test_get_latest_and_install_eden ... ok
开始测试:获取最新版本并安装 Eden
步骤 1: 获取最新版本
最新版本: v1.0.0
步骤 2: 创建临时安装目录
临时目录: C:\Users\...\Temp\...
步骤 3: 开始下载并安装 Eden v1.0.0
Eden 下载 15.2% (8/52 MB) @ 1024 KB/s
Eden 下载 35.8% (18/52 MB) @ 2048 KB/s
Eden 下载 58.4% (30/52 MB) @ 2048 KB/s
Eden 下载 81.7% (42/52 MB) @ 2048 KB/s
Eden 下载 99.9% (52/52 MB) @ 2048 KB/s
步骤 4: 验证安装结果
Eden 安装路径: C:\Users\...\Temp\...\emulator\eden.exe
测试完成: Eden v1.0.0 安装成功
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 4 filtered outOverview (`frontend/src/components/README.md`)
Components
Vue template files in this folder are automatically imported.
🚀 Usage
Importing is handled by unplugin-vue-components. This plugin automatically imports .vue files created in the src/components directory, and registers them as global components. This means that you can use any component in your application without having to manually import it.
The following example assumes a component located at src/components/MyComponent.vue:
<template>
<div>
<MyComponent />
</div>
</template>
<script lang="ts" setup>
//
</script>When your template is rendered, the component's import will automatically be inlined, which renders to this:
<template>
<div>
<MyComponent />
</div>
</template>
<script lang="ts" setup>
import MyComponent from '@/components/MyComponent.vue'
</script>Overview (`frontend/src/layouts/README.md`)
Layouts
Layouts are reusable components that wrap around pages. They are used to provide a consistent look and feel across multiple pages.
Full documentation for this feature can be found in the Official vite-plugin-vue-layouts repository.
Overview (`frontend/src/plugins/README.md`)
Plugins
Plugins are a way to extend the functionality of your Vue application. Use this folder for registering plugins that you want to use globally.
Overview (`frontend/src/stores/README.md`)
Store
Pinia stores are used to store reactive state and expose actions to mutate it.
Full documentation for this feature can be found in the Official Pinia repository.
Overview (`frontend/src/styles/README.md`)
Styles
This directory is for configuring the styles of the application.
Dev (`docs/dev.md`)
Dev
当前技术栈
项目现在已经从旧的 Python/Eel 方案切换到 Rust + Tauri 2:
- 桌面端后端:Rust(
src-tauri) - 前端:Vue 3 + Vite + Vuetify(
frontend) - 前端构建产物:
web
本文档中的开发流程以当前的 Rust/Tauri 架构为准,旧的 Python 启动方式已经不再适用。
开发环境需求
- Rust stable 工具链(
rust-version = 1.70及以上) - Tauri CLI
- Bun
- Node.js 20+
如果你在 Windows 上开发,通常还需要:
- Visual Studio C++ Build Tools(MSVC)
- WebView2 Runtime
环境准备
Step 1 安装前端依赖
cd frontend
bun installStep 2 安装 Tauri CLI
如果本机还没有安装 Tauri CLI,可以执行:
cargo install tauri-cliStep 3 确认 Rust 工具链
rustup show
cargo --version本地运行
在 src-tauri 目录启动 Tauri 开发模式:
cd src-tauri
cargo tauri dev说明:
cargo tauri dev会读取src-tauri/tauri.conf.json- 会自动执行前端 dev server(
bun run --cwd ../frontend dev) - 前端默认运行在
http://localhost:3000
前端单独调试
如果只想调试页面样式或交互,可以单独启动 Vite:
cd frontend
bun dev需要注意,这种方式只会启动前端页面;如果页面依赖 Tauri 的 Rust 命令,仍然建议通过 cargo tauri dev 联调。
构建
仅构建前端资源
cd frontend
bun build构建结果会输出到项目根目录下的 web。
构建桌面应用
cd src-tauri
cargo tauri build说明:
cargo tauri build会自动调用前端构建命令- 最终产物由 Tauri 按平台进行打包
Rust 开发与检查
Rust 代码主要位于:
src-tauri/src/commands:Tauri 命令入口src-tauri/src/services:核心业务逻辑src-tauri/src/repositories:数据访问与平台适配src-tauri/src/models:数据模型
日常开发建议至少执行:
cd src-tauri
cargo fmt
cargo check如需运行测试:
cd src-tauri
cargo test调试建议
- 调试前后端联动时,优先使用
cargo tauri dev - 调试 Rust 逻辑时,可直接使用支持 Rust 的 IDE(如 RustRover、VS Code + rust-analyzer)
- 修改前端后如需验证最终构建结果,可先执行
bun build,再执行cargo tauri build
说明
以下旧流程已经废弃,不再适用于当前项目:
poetry run python main.pyuv run python ui.pyuv sync- 基于 Eel/gevent 的 Python 调试方式
Plan Citron Stable Nightly Branches Plan (`docs/plan/citron-stable-nightly-branches-plan.md`)
Citron Stable/Nightly 分支拆分计划
背景
当前 Yuzu 页面把 Citron Neo 作为单一分支 citron 展示和处理,而 Citron Neo 模拟器自身的更新检查已经把 Stable 与 Nightly 作为两个渠道:
- Stable release 源:
https://api.github.com/repos/citron-neo/emulator/releases - Nightly release 源:
https://api.github.com/repos/citron-neo/CI/releases
本计划目标是把现有下拉列表里的 “Citron” 拆成 “Citron Stable” 与 “Citron Nightly” 两项,交互方式参考 Ryujinx 的 Mainline/Canary 分支。
目标
- 前端 Yuzu 页面下拉列表展示独立的
Citron Stable与Citron Nightly。 - 后端分支参数支持稳定的内部值,例如
citron-stable与citron-nightly。 - 旧配置中的
citron保持兼容,默认迁移或等价映射到citron-stable。 - 获取版本、安装、变更日志、检测当前安装版本和分支时,都能正确区分两个 Citron 渠道。
- 现有 Eden 行为不受影响。
设计
分支命名
新增 Yuzu 分支值:
citron-stable:对应 Citron Neo Stable。citron-nightly:对应 Citron Neo Nightly。
兼容旧值:
citron继续被后端接受,按citron-stable处理。- 配置加载或分支切换时可逐步把
citron写回为citron-stable,避免旧用户下拉框无选中项。
Release 数据源
在 src-tauri/src/repositories/yuzu.rs 中拆分 Citron release API:
- Stable 使用 GitHub Releases API,走
request_github_api和ReleaseInfo::from_github_api。 - Nightly 使用 GitHub Releases API,走
request_github_api和ReleaseInfo::from_github_api。 - Nightly 的版本号不使用平台 tag(例如
nightly-windows),而是从body/name/ 资产名中提取Citron Upstream Commit的短 SHA,例如fab192f。同一个 upstream SHA 下的 Windows、macOS、Linux release 资产需要合并成同一个版本条目,安装时再按当前平台筛选资产。 - 上游 Citron Neo updater 源码曾出现
https://git.citron-neo.org/api/v1/repos/Citron/Emulator/releases这种 Forgejo/Gitea 风格 API,但当前环境无法解析该域名;本工具应优先使用当前可访问且现有代码已在使用的 GitHub API。
需要更新的入口:
get_all_yuzu_release_versions(branch)get_yuzu_all_release_info(branch)get_yuzu_release_info_by_version(version, branch)get_latest_change_log(branch)- unsupported branch 错误文案和测试
安装与资源选择
在 src-tauri/src/services/yuzu.rs 中统一分支判断:
- 所有 Citron 变体共用安装路径、可执行文件名、用户目录识别和 macOS bundle 校验逻辑。
- 资源选择不应依赖资产名中的
stable或nightly文本来判断渠道。当前citron-neo/emulator的 tagged release 源虽然作为 Stable 使用,但桌面资产名仍可能是Citron-windows-nightly-...、Citron-macOS-nightly-...、citron_nightly-...AppImage。 - Stable/Nightly 渠道由用户选择的分支值和对应 release API 决定;资产名只用于筛选平台、架构、包格式和工具链。
- Windows 继续优先选择非 PGO 的
.zip,并沿用现有 Citron 偏好x64-msvc、再回退x64-clangtron的策略。 - macOS 继续选择
.dmg,并排除.zsync等增量更新文件。 - Linux 当前仍按既有支持策略处理 AppImage,不把文件名中的
nightly当作渠道判断条件。 - 如果当前逻辑只判断
branch == "citron",改成辅助函数,例如is_citron_branch(branch)。 - 安装完成写入配置时保存具体分支值,优先保存用户选择的
citron-stable或citron-nightly。
版本和分支检测
当前检测逻辑已经能从窗口标题、版本字符串或可执行文件元数据识别 Citron。需要补齐:
- 检测到 Citron 但无法确定渠道时,默认返回
citron-stable,与旧citron兼容语义保持一致。 - 不应仅凭安装包或资产名包含
nightly就判定为citron-nightly,因为 Stable 源的 tagged release 资产名也可能带nightly。 - 如果版本文件、配置或明确元数据能证明来自 Stable 源,返回
citron-stable。 - 如果明确来自 CI/nightly 源,或 release/tag 元数据指向
citron-neo/CI,返回citron-nightly。 - 对本地已安装 Citron 但无法可靠判断渠道的情况,默认返回
citron-stable。 - 旧的
citron检测结果在写入配置前规范化为citron-stable。
前端
在 frontend/src/pages/yuzu.vue 中更新 branches:
EdenCitron StableCitron Nightly- 已关闭的 Yuzu 主线/EA 保持原状
branchMap、selectedEmulatorName、版本加载、安装和切换逻辑继续使用分支 value 传给 Tauri。初始化时如果配置里读到旧值 citron,前端也应显示为 citron-stable,避免空选中。
相关类型和默认配置可同步检查:
frontend/src/types/index.tsfrontend/src/types/DefaultConfig.tsfrontend/src/utils/tauri.ts
实施步骤
- 增加 Rust 侧分支常量和规范化函数,例如
normalize_yuzu_branch、is_citron_branch、is_citron_stable_branch、is_citron_nightly_branch。 - 拆分
repositories/yuzu.rs中 Citron Stable/Nightly 的 release API 与解析函数。 - 调整
services/yuzu.rs中所有 Citron 分支判断,让安装、资源筛选、检测和配置写入使用规范化分支。 - 调整
commands/yuzu.rs,确保switch_yuzu_branch、安装和版本查询都接受新分支值。 - 更新
frontend/src/pages/yuzu.vue下拉列表和旧citron映射。 - 增加或更新 Rust 单元测试,覆盖分支规范化、release 解析、资产选择和旧
citron兼容。 - 如前端有测试或类型检查脚本,补跑对应校验。
验证
修改 Rust 后按仓库要求执行:
cargo fmtcargo check- Windows target 的
cargo check - 如果从 Windows 验证 macOS target,使用
cargo zigbuild
功能验证项:
- Yuzu 页面下拉框能看到
Citron Stable与Citron Nightly。 - 两个 Citron 分支分别加载不同 release 源的版本列表。
citron-nightly版本列表显示 upstream 短 SHA,例如fab192f,而不是nightly-windows这类平台 tag。- 选择任一 Citron 分支后安装时下载所选 release 源中的平台匹配资产,即使 Stable 源资产名包含
nightly也不应被排除。 - 旧配置
branch: "citron"打开后仍可正常加载,并落到 Stable 兼容路径。 - Eden 安装和版本列表不受影响。
纯后端端到端验证项:
- 为
citron-stable和citron-nightly各跑一次版本列表获取,确认返回非空列表,且请求源分别是citron-neo/emulator与citron-neo/CI。 - 确认
citron-nightly返回的版本值是 7 位 upstream 短 SHA,并且用该 SHA 继续调用 release 详情能反查到对应 release 与资产。 - 对两个分支各取最新版本调用 release 详情接口,确认能解析 release 元数据和资产列表。
- 对两个分支各跑一次下载 URL 解析或安装前校验流程,确认能选出当前平台可用资产;Stable 源资产名包含
nightly时也必须通过。 - 通过 Tauri command 层或 Rust 集成测试调用
get_all_yuzu_versions/install_yuzu_by_version的后端路径,覆盖从分支参数进入到 repository/service 的完整链路。 - 如果真实安装会写入本机模拟器目录,端到端测试应使用临时目录或只验证到下载 URL 选择阶段,避免污染用户现有安装。
风险
- Stable 与 Nightly 都是 GitHub Releases API,字段形态一致,核心字段为
tag_name、name、body、published_at、assets[].name、assets[].browser_download_url。风险不在 JSON schema,而在两个仓库的发布策略和资产命名是否持续稳定。 - Nightly 的可选版本依赖
Citron Upstream Commit或资产名中的 upstream SHA;如果 CI release 文案或资产命名规则变化,可能需要更新 SHA 提取逻辑。 - 上游源码里保留过
git.citron-neo.org/api/v1/...的 Stable URL,但该域名当前不可解析;不要把它作为本工具的默认 Stable 源,除非后续确认官方恢复该域名。 - Stable 源资产名目前也带
nightly,因此资产名不能作为渠道判定依据;只能作为平台、架构、格式和工具链筛选依据。 - 旧用户配置、历史路径和检测结果如果仍写入
citron,前端可能出现下拉框选中状态不一致,需要统一规范化。
--- METRICS ---
- Files Extracted: 10
- Estimated Token Budget: ~4790 tokens
- Canonical Reference: https://codewiki.google/github.com/triwinds/ns-emu-tools