Metadata-Version: 2.4
Name: modelscope-multi-proxy-download
Version: 1.0.2
Summary: Multi-proxy, chunked, resumable downloader for ModelScope repositories
License: Apache-2.0
Project-URL: Homepage, https://pypi.org/project/modelscope-multi-proxy-download/
Project-URL: Repository, https://github.com/gbdjxgp/modelscope-multi-proxy-download
Project-URL: Issues, https://github.com/gbdjxgp/modelscope-multi-proxy-download/issues
Keywords: modelscope,download,proxy,resume,mirror
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: System :: Networking
Requires-Python: >=3.8
Description-Content-Type: text/markdown
Requires-Dist: requests>=2.28

# modelscope-multi-proxy-download

用多条代理线路并发下载 ModelScope 模型仓库的命令行工具，用来替代 `modelscope download`。

大文件自动切块并分配到不同代理同时下载，下载与合并并行进行；中断后可断点续传，落盘前校验 SHA256；某条代理挂掉会自动跳过，恢复后自动重新启用。

```bash
modelscope_multi_proxy_download Qwen/Qwen3-8B --proxy proxies.txt
```

## 安装

```bash
python3 -m pip install -U -i https://pypi.tuna.tsinghua.edu.cn/simple modelscope-multi-proxy-download
```

或者用 `uv` 免安装直接运行：

```bash
uvx --default-index https://pypi.tuna.tsinghua.edu.cn/simple \
  --from modelscope-multi-proxy-download \
  modelscope_multi_proxy_download --help
```

装好后有两个命令，`modelscope_multi_proxy_download` 和简写 `msmpd`，用哪个都一样。

本工具只依赖 `requests`，不需要安装 `modelscope` SDK。

## 快速开始

### 一条代理

```bash
msmpd Qwen/Qwen3-8B --proxy http://127.0.0.1:7890
```

不加 `--local_dir` 时，默认下载到当前目录下的 `Qwen3-8B/`（取 model_id 最后一段）。

### 多条代理

`--proxy` 可以重复传，每条线路都会参与下载：

```bash
msmpd Qwen/Qwen3-8B \
  --proxy http://127.0.0.1:10090 \
  --proxy http://127.0.0.1:10091
```

### 用代理列表文件

把 `--proxy` 的值写成文件路径，工具会自动按行读取：

```bash
msmpd Qwen/Qwen3-8B --proxy proxies.txt
```

`proxies.txt`：

```txt
# 支持 # 注释和空行，省略协议时默认按 http:// 处理
http://127.0.0.1:10090
127.0.0.1:10091
socks5h://127.0.0.1:1080
DIRECT
```

`DIRECT` 表示本机直连。默认就会自动加上直连线路，不需要显式写；如果你只想走代理，加 `--no-direct`。

文件路径和代理地址可以混着传：

```bash
msmpd Qwen/Qwen3-8B --proxy proxies.txt --proxy http://127.0.0.1:7890
```

### 只下载部分文件

```bash
msmpd Qwen/Qwen3-8B --include '*.safetensors' --include '*.json'
msmpd Qwen/Qwen3-8B --exclude '*.bin'
```

两者同时给出时 `--include` 优先。也可以直接在命令行点名要哪几个文件：

```bash
msmpd Qwen/Qwen3-8B config.json tokenizer.json
```

### 先检查代理通不通

```bash
msmpd Qwen/Qwen3-8B --proxy proxies.txt --check-only
```

## 工作方式

### 大文件切块 + 多代理并发

超过 `--chunk-min-size-mb`（默认 200MB）的文件会按 `--chunk-size-mb`（默认 200MB）切成多个块，放进一个统一的任务队列；每条代理作为消费者不断从队列里领取块来下载。

队列**按 `(文件序号, 块序号)` 排序**，不是先进先出。这一个设计同时带来两个效果：

- 所有代理会先集中把靠前的文件下完，而不是把带宽摊到整个仓库上，因此文件能尽早完成、尽早合并；
- 某个块下载到一半失败或代理挂了，它会**以原优先级重新入队**，也就是回到队列最前面，被下一条空闲线路立刻接手。

小文件不切块。ModelScope 对仓库里的小文件（普通 git blob）不支持 Range 请求，切了反而会失败；只有大文件（LFS 对象）才真正支持分段下载。

### 下载与合并并行

某个文件的最后一个块落盘后，它会被立刻交给独立的合并线程，一边拼接一边算 SHA256，主线程的代理们继续下载后面的文件，两件事互不等待。合并线程数用 `--merge-workers` 控制。

### 断点续传

分块文件存成 `<文件名>.part.<起>-<止>`，单块文件直接存成 `<文件名>.incomplete`（和官方客户端同名，两边可以接力续传）。

**块文件自身的大小就是进度记录**，没有额外的状态文件，因此不存在状态文件和实际数据对不上的情况。中断后重新执行同一条命令即可续传。

即使你改了 `--chunk-size-mb`，工具也会从已有的块文件名反推出上一次用的切块网格并沿用，不会把已下载的数据作废重下。

### 校验

文件列表里带的 SHA256 会在合并时顺带算出来比对，不需要额外读一遍磁盘。校验不通过会删掉重下，最多重试 `--file-retries` 次（默认 3）。已经存在且大小相符的文件由多个验证 worker 并行校验；校验与下载同时进行，任一文件校验失败后会立即进入下载队列，不会等待其他文件验证完成。终端会显示每个验证 worker 的进度。用 `--verify-workers` 调整验证并发数，用 `--no-verify` 可以关掉校验。

### 代理故障处理

- 下载前会并发探测每条线路，探测失败的不会拿到第一个块。
- 运行中失败的线路进入指数退避冷却（5s、10s、20s…最多 120s），冷却结束自动重新参与。
- 连续失败达到 `--route-max-failures`（默认 6）次的线路被判定为不可用，直接跳过。
- 连接虽然活着但速度长期低于 `--min-speed-kb`（默认 20KB/s，持续 `--slow-window-sec` 60 秒）时，主动断开换线路重试——已下载的部分不会丢。
- 如果所有线路都挂了，会整体重试若干轮再放弃，避免一次网络抖动导致整个任务失败。

## 常用参数

完整列表见 `msmpd --help`。

| 参数 | 说明 |
| --- | --- |
| `--local_dir DIR` | 下载目录，默认取 model_id 最后一段 |
| `--cache_dir DIR` | 改用 ModelScope 缓存目录布局 |
| `--revision REV` | 分支、标签或 commit，默认 `master` |
| `--token TOKEN` | 私有仓库的访问令牌，也可用 `MODELSCOPE_API_TOKEN` 环境变量 |
| `--proxy URL_OR_FILE` | 代理地址或代理列表文件，可重复 |
| `--no-direct` | 不使用本机直连 |
| `--max-workers N` | 并发传输数，默认每条线路一个。设得比线路数大就是每条代理开多个连接 |
| `--chunk-size-mb N` | 切块大小，默认 200，设 0 表示不切块 |
| `--chunk-min-size-mb N` | 达到多大才切块，默认 200 |
| `--merge-workers N` | 合并线程数，默认 1 |
| `--verify-workers N` | 已有文件的并行校验线程数，默认 4 |
| `--include GLOB` / `--exclude GLOB` | 按 glob 过滤文件，可重复 |
| `--force` | 已存在的文件也重新下载 |
| `--no-verify` | 跳过 SHA256 校验 |
| `--dry-run` | 只列出将要下载的文件 |
| `--check-only` | 只检测线路连通性 |
| `--no-progress` | 关闭实时进度显示（写日志文件时建议加上） |
| `--version` | 显示版本并退出 |

退出码：`0` 成功，`1` 有文件失败，`2` 参数错误，`130` 被 Ctrl-C 中断。

## 搭配 Windows 代理使用

### 场景 A：Linux 下模型，借用 Windows 的网络

1. Windows 上起一个代理，监听 8888：

```powershell
uvx --default-index https://pypi.tuna.tsinghua.edu.cn/simple --from proxy-py proxy --hostname 0.0.0.0 --port 8888
```

2. Windows 主动连到 Linux，做反向端口转发：

```powershell
ssh -N -R 8888:127.0.0.1:8888 linux_user@linux_ip
```

3. Linux 上下载，代理填本机 8888：

```bash
msmpd Qwen/Qwen3-8B --proxy http://127.0.0.1:8888
```

### 场景 B：Windows 下模型，借用 Linux 的网络

1. Linux 上起代理：

```bash
uvx --default-index https://pypi.tuna.tsinghua.edu.cn/simple --from proxy-py proxy --hostname 0.0.0.0 --port 8888
```

2. Windows 做本地端口转发：

```powershell
ssh -N -L 8888:127.0.0.1:8888 linux_user@linux_ip
```

3. Windows 上下载：

```powershell
msmpd Qwen/Qwen3-8B --proxy http://127.0.0.1:8888
```

多台机器各出一条线路时，把它们分别转发到不同本地端口，然后一起写进 `proxies.txt` 即可。

## 从 0.x 升级

0.x 的参数都还能用，会自动映射到新参数，老脚本不用改：

| 0.x 参数 | 现在 |
| --- | --- |
| `--allow-pattern` / `--ignore-pattern` | 等价于 `--include` / `--exclude` |
| `--multi-route-part-size-mb` | 等价于 `--chunk-size-mb` |
| `--multi-route-min-size-gb` | 等价于 `--chunk-min-size-mb`（单位换成 MB） |
| `--no-multi-route-large-files` | 等价于 `--chunk-size-mb 0` |
| `--check-proxies` / `--check-timeout` | 等价于 `--check-only` / `--probe-timeout` |
| `--no-worker-progress` | 等价于 `--no-progress` |
| `--no-route-fallback` | 已移除，失败任务总是会换线路重试 |

行为上的主要变化：

- 不再依赖 `modelscope` SDK，直接调用 Hub 的 HTTP 接口，安装体积和版本兼容问题都少了很多；
- 每条线路通过 `proxies=` 显式指定，不再改 `http_proxy` 环境变量，因此不用再为每条代理开一个子进程；
- 所有文件走同一套切块/续传/校验流程，不再有"普通文件"和"大文件多路"两条独立代码路径。

## License

Apache-2.0
