How GolinksPRO Download Manager's pieces fit together.
Crates
| 路径 | Crate | 作用 |
|---|---|---|
crates/engine |
mdm-engine |
通过 HTTP(S) 或 FTP(S) 下载单个文件:探测、分段规划器、连接工作器、恢复状态、每主机限制、速度限制器、校验和、代理脚本 |
crates/app |
mdm-app |
桌面应用(misterdownloadmanager.exe,egui):列表、类别、队列、调度器、对话框、托盘、设置 |
crates/cli |
mdm-cli |
无界面下载,带进度(get、resume)、视频、种子和自动化API命令:应用程序运行的库(misterdownloadmanager --cli …),以及misterdownloadmanager-cli,一个小型启动器,以相同的参数、终端和退出代码启动它 |
crates/mcp |
mdm-mcp |
MCP 服务器(misterdownloadmanager-mcp):AI 助手通过自动化 API 列出、添加和控制正在运行的应用的下载 |
crates/remote |
mdm-remote |
远程控制 (#141):本地网络上已配对的手机或电脑使用的 HTTPS 服务器(其页面、配对码、设备令牌、自签名证书);每个请求都成为应用响应的自动化 API 命令 |
crates/nmhost |
mdm-nmhost |
浏览器的原生消息主机:从扩展程序获取捕获的下载并将其交给应用 |
crates/ipc |
mdm-ipc |
应用和主机共享的单实例通道(受令牌保护的本地套接字)、数据文件夹和捕获规则 |
crates/debrid |
mdm-debrid |
Debrid 账户 (#44):这些服务的官方 API(Real-Debrid、AllDebrid、Premiumize)将文件托管链接转换为引擎可直接下载的链接 |
crates/extract |
mdm-extract |
档案解压 (#37):zip、tar、gz 和 xz 正在处理中;7z 和 RAR 通过已安装的 7-Zip 程序运行 |
crates/geo |
mdm-geo |
下载服务器位置 (#140):根据 DB-IP Lite 数据 (tools/geo/build.py) 构建的 IP 到国家/地区范围表,仅在此计算机上查找,并显示国家/地区旗帜 |
crates/tools |
mdm-tools |
Video pages through yt-dlp and ffmpeg, image galleries through gallery-dl (run as separate programs); while a network adapter is chosen, their connections go through a proxy of GDM's on 127.0.0.1 that binds them to it (relay.rs) |
crates/crash |
mdm-crash |
崩溃和冻结报告:监视进程、进程外 minidumps、符号化堆栈、报告文本和发布日志(crash-reports.md) |
crates/torrent |
mdm-torrent |
通过 librqbit 处理 BitTorrent 和磁力链接 |
crates/labserver |
mdm-labserver |
一个带请求日志和故障注入的 HTTP Range 服务器,以及一个带自身故障的 FTP/FTPS 服务器,用于测试和基准测试 |
extension/ |
— | Chromium (MV3) 和 Firefox 扩展程序 |
docs/ |
— | 用户指南和教程,此文件,基准数据;网站将此指南作为其帮助页面,点击“帮助”即可打开 |
website/ |
— | misterdownloadmanager.com 自己的页面(主页、下载、功能、主题、常见问题);tools/website/build.py 添加了来自 docs/ 的帮助和来自 CHANGELOG 的新闻,共 22 种语言,由 GitHub Pages 发布 |
依赖项指向内部:app、cli、mcp、nmhost 和 remote 使用 engine 和 ipc;引擎对 UI 一无所知。应用仅通过其事件(进度、分段表快照、完成、失败)查看引擎。
引擎
Download
├─ probe() size, resumable?, validators (ETag / Last-Modified), file name
├─ Planner (pure) segment table: when a connection is free, the largest remaining
│ part is split in half (planner.rs, tested by random simulation)
├─ Worker × N one HTTP/1.1 connection each, reused across segments; slow ones
│ are dropped and their part re-split
│ └─ writes at its offset into <name>.mdm.part (created sparse)
├─ HostLimits learns how many connections each server accepts
├─ Limiter (shared) per-download and global token buckets
├─ State segment table saved atomically (craft-atomic) for crash-safe resume
└─ events → channel Progress, Done, Failed
当所有分段完成后,部分文件会根据预期大小进行检查并重命名到位;文件的日期可以跟随服务器的日期。
下载的第一个请求 (get) 会跟踪重定向以及那些自行导向文件的页面(例如等待页面的刷新)。如果网站的链接不是文件地址,sites/ 中会有一个模块(例如 Google Drive: sites/gdrive.rs):它将链接转换为文件地址,读取网站自己的页面(例如确认表单、错误页面),并指出其拒绝原因 (Error::Refused),所有这些都通过无需网络即可测试的纯函数实现。实验室服务器会在其真实主机名上模拟此类网站,以进行端到端测试 (labserver/src/drive.rs)。
FTP 和 FTPS(ftp.rs)通过相同的规划器、工作器和状态:一个分段是控制会话上的 REST + RETR,而不是范围 GET,SIZE 和 MDTM 代表头部,会话按下载进行池化并在分段之间重用。
应用
一个 egui 窗口绘制到固定的像素坐标,每个对话框一个即时视口。app.rs 维护状态(下载、队列、设置、列表选择),并将菜单、工具栏、按键和 IPC 命令转换为操作。每个对话框都是独立的模块,并返回一个 Outcome(打开、关闭、完成并带有一个值)。仅限 Windows 的调用限于 win32.rs,其 Linux 和 macOS 对应部分限于 unix.rs(会话启动、浏览器主机、声音、在文件夹中显示、崩溃处理程序);其他所有文件都是安全、可移植的 Rust 代码。字体来自系统:Windows 的 Fonts 文件夹、macOS 的系统字体、Linux 上的 fontconfig (theme.rs)。在 Windows 上,拉丁文、希腊文和西里尔文文本由 DirectWrite 在 GDI 经典模式下绘制 (win32.rs,通过 egui 的字形栅格化器钩子),因此每个字母的提示形状和整像素宽度得以结合;其他脚本由 egui 进行整形和绘制。
主题
控件绘制的每种颜色和大小都来自活动主题 (#45)。一个主题包含一个亮色和暗色调色板、度量、控件样式和图标样式 (palette.rs):
- 调色板角色。
palette.rs声明每个角色都有一个稳定的键("button.hot"、"list.row"、"caption"…)、一个描述以及经典外观的亮色和暗色值,明确写出(经典外观并非派生)。共享的绘图器(winui.rs、chrome.rs、list.rs、scrollbar.rs)通过theme::colors()和theme::metrics()读取它们,并根据它们决定每个控件的状态;没有绘图代码拥有自己的颜色。 - 派生调色板。
derive.rs从几个种子(背景、表面、文本、强调色…)生成完整的调色板,在 OKLab 中混合所有其他角色并保持 WCAG 对比度(文本 4.5:1,边缘 3:1);高对比度会加强所有边缘。native.rs根据系统的强调色和对比度(Windows 设置、Linux 上的 freedesktop 门户、macOS 的强调色)为“原生”主题提供种子。 - Control styles.
palette::Controlsnames each control's shape (text boxes, check boxes, buttons, progress bars, scroll bars, the focus mark, the title bar); the style themes (Metro, Adwaita, Breeze, Luna, Aero, Aqua) pick theirs, and on Windows GDM then draws the title bar itself (thecaption.*roles). - 主题文件。
themefile.rs从数据文件夹的themes读取 TOML 或 JSON(一个文件,或<id>/theme.toml旁边带有图标)。一个文件只命名它所更改的内容;其余部分来自它inherits的主题(内置主题的 ID 或另一个文件,默认是经典外观),沿着一个拒绝循环的链。未知键是警告,而不是错误。内置样式主题也是此类文件,包含在程序中(crates/app/assets/themes)。 - 图标集。
themeicons.rs绘制主题的图标(按用途命名:tb-add-url、cat-music…,16、24、32 和 48 像素的 SVG 或 PNG,-symbolic的图标以文本颜色着色),在经典外观绘制自己的图标的地方;如果图标集缺少所需图标,则保留经典图标。
窗口放置控件的位置保持其布局不变。文件名前的图标也是如此 (fileicons.rs):Windows shell 的系统图像列表、macOS Finder 的 (NSWorkspace)、Linux 桌面的图标主题 (xdgicons.rs、shared-mime-info 和图标主题规范)。每种类型按像素大小查找一次,在后台线程上进行。Tango 的图标(捆绑)在系统图标准备好之前以及系统没有图标的地方作为替代。
绘图
The windows are drawn with OpenGL (eframe's glow) or with the system's own graphics API through
eframe's wgpu, with that one backend only: Direct3D 12 on Windows (the default there), Vulkan on
Linux, Metal on macOS (choices there; OpenGL stays their default until real graphics cards have
tried them, #206). View → Draw with picks one, from the next start. One code path does it on
every system (crates/app/src/renderer.rs): when the chosen one can't start, the other one is
tried, so the windows always open. A watched start with the system's API leaves a marker until
its first frame is drawn: a start that ends before it (a crash inside the driver), one whose
first frame doesn't come within 10 seconds (GDM then starts again with OpenGL), or a graphics
card lost twice in 10 minutes is remembered with its reason, which the menu shows.
“视图”→“界面大小”(scale.rs, #262) 是 egui 在显示器自身缩放比例之上的缩放因子:每个窗口都以点为单位布局,因此它会按比例放大;如果大于屏幕,则会滚动。
数据
下载列表和设置以原子方式保存到数据文件夹 (downloads.json):Windows 上的 %APPDATA%\misterdownloadmanager\,Linux 上的 ~/.local/share/misterdownloadmanager,macOS 上的 ~/Library/Application Support/misterdownloadmanager,便携式副本旁边的 data 文件夹,或 MDM_DATA_DIR (mdm_ipc::data_dir)。浏览器主机读取相同的文件以获取捕获规则,因此“选项”中的更改适用于下一个捕获的下载。
Sign-in secrets (debrid accounts, Sites Logins' and the proxy's passwords) live in the system's
keychain (secrets.rs, #44): Windows Credential Manager (win32.rs), the Secret Service on Linux
or the macOS keychain (unix.rs). The settings keep a keychain:<service>/<scope>/<key>
reference in their place, written only once the keychain has confirmed the secret; without a
keychain (or with a locked one, never unlocked for GDM) the secret stays in the settings as
before.
下载的服务器位置 (#140) 是其连接到的地址所在国家/地区,在此计算机上通过 mdm-geo 的表格查找(countries.rs 以界面语言命名);发布任务会根据当月数据重新构建表格 (tools/geo/build.py --release)。
浏览器集成
page ──► extension ──native messaging──► mdm-nmhost ──ipc──► app
扩展程序会询问主机要获取哪些文件类型,对照这些类型检查每个下载,并且仅在应用程序接受后才取消浏览器的下载;否则浏览器会保留它,扩展程序会说明原因。
The host serves only GDM's own extension. Its IDs are in one place, mdm_ipc::extension
(crates/ipc/src/extension.rs): the unpacked copy's (UNPACKED_ID, from the manifest's public
key), the Chrome Web Store's (STORE_ID, signed with the store's own key: pack.ps1 leaves the
manifest's key out of the store's copy), the Firefox add-on's (FIREFOX_ID) and its
addons.mozilla.org page; the Edge and Opera stores' are placeholders, never served, until the
extension is listed there. The host writes each browser's manifest with those IDs, and the app
offers the store's copy (Add to Chrome, Add to Firefox) before the unpacked one.
远程控制
phone ──HTTPS (paired token)──► mdm-remote ──ipc::Sink──► app (answer, remote_add)
--headless(headless.rs, #157) 运行相同的 App 而不使用 eframe:一个循环在裸 egui::Context 上调用其 tick(logic 在每一帧运行的内容),由命令通道唤醒,从不调用其 ui;命令由远程控制添加(无窗口)。Dockerfile 和 docker/(Compose、Unraid 的模板)在服务器上运行它(server.md)。
服务器在应用的 Tokio 运行时上运行,每个本地网络地址一个监听器。每个请求都经过检查(Host、Origin、令牌),转换为标记为 mdm_ipc::Command 的 remote(请求行无法设置的字段),并通过与命令行相同的通道传递给应用;应用在下一帧响应它,就像响应自动化 API 一样。其页面内置于 crates/remote/web 中,其文本来自应用的目录 (remote.rs)。
翻译
UI 显示的每个文本都通过 crate::i18n(craft-i18n 目录,i18n/<locale>.tsv)。tools/i18n/extract.py 从源代码重建 i18n/en.tsv,并为每个文本附上翻译人员的注释(它是什么,在哪里显示,其占位符)。tools/i18n/translate.py 填充其他目录中缺少的内容(标记为 #, machine 的行),遵循每种语言的样式指南(i18n/style/)和词汇表;人工审核过的行永远不会被替换,CI(reviewed_guard.py)会使删除行的更改失败。网站有自己的目录(i18n/site/,tools/website/translate_site.py)。
图片
The help pages' pictures (docs/images/help/) come from one list, tools/shots/shots.toml:
tools/shots/make.py opens each window through GDM's own /show <window> command line in a test
instance off the screen, crops and annotates it from the window's accessibility tree, and writes
lossless WebP; make.py check (CI) keeps the list, the pages and the files in step. The
published ones are taken on GitHub's Windows runner (docs-shots.yml).
贡献者
tools/contributors.py从 GitHub 的公共 API 读取谁发起了拉取请求和问题,以及谁发表了评论(维护者、Claude 和机器人除外),用于感谢他们的所有地方:网站主页、/contributors.html 和新闻页面上的每个版本(build.py,在每个构建中),每个版本的发布说明(release.yml,自上一个版本以来活跃的人员)以及 README(python tools/contributors.py readme 在每个版本准备时:其圆形照片提交在 art/contributors/ 中,因为 GitHub 无法在 README 中将图片设为圆形)。
测试和基准
cargo test针对注入故障(慢速、丢弃和拒绝连接、无范围服务器、文件更改)的 mdm-labserver 运行单元测试和端到端下载。tools/bench 运行已发布的速度比较;其原始数据在 docs/bench/ 中。
免费、开源、无广告、无试用版。
Download GolinksPRO Download Manager