MHTI 是一个全栈 Web 应用,专为媒体文件管理设计。它能够自动解析视频文件名,从 TMDB 获取元数据,生成 NFO 文件,并智能整理媒体库,完美兼容 Emby/Jellyfin 等媒体服务器。
功能模块
说明
🎬 文件名解析
智能解析多种命名格式(标准、中文、日文等),自动修正季号
🔍 TMDB 集成
自动搜索匹配,获取剧集/电影元数据,核验季集存在性
📝 NFO 生成
生成 Emby/Jellyfin 兼容的 NFO 文件
📁 文件整理
支持复制/移动/硬链接/软链接四种模式
☁️ 115 网盘
扫码登录 115 网盘,支持 115→115/115→本地 整理
🖼️ 图片下载
自动下载海报、背景图、剧集缩略图
📺 字幕关联
自动识别并关联同名字幕文件
👁️ 文件夹监控
实时/兼容/事件三种模式,支持本地与 115 网盘目录
🔗 Emby 集成
媒体库冲突检测,避免重复
🔐 安全认证
JWT 认证,多会话管理
🌙 主题切换
支持亮色/暗色主题
graph TB
subgraph Client["🌐 客户端"]
Browser[浏览器]
end
subgraph Docker["🐳 Docker 容器"]
subgraph Gateway["网关层"]
Caddy[Caddy<br/>反向代理<br/>端口 8000]
end
subgraph Frontend["前端层"]
Vue[Vue 3 SPA<br/>静态文件]
end
subgraph Backend["后端层"]
FastAPI[FastAPI<br/>REST API]
WebSocket[WebSocket<br/>实时通信]
end
subgraph Services["服务层"]
ScraperSvc[ScraperService<br/>刮削编排]
TMDBSvc[TMDBService<br/>元数据获取]
ParserSvc[ParserService<br/>文件名解析]
NFOSvc[NFOService<br/>NFO生成]
ImageSvc[ImageService<br/>图片下载]
P115Svc[P115Service<br/>115 网盘]
WatcherSvc[WatcherService<br/>文件监控]
RenameSvc[RenameService<br/>文件整理]
SchedulerSvc[SchedulerService<br/>定时任务]
end
subgraph Core["核心层"]
Container[DI 容器]
Database[(SQLite)]
Auth[JWT 认证]
end
end
subgraph External["🌍 外部服务"]
TMDB[TMDB API]
Emby[Emby Server]
P115["115 网盘<br/>生活事件 API"]
end
Browser --> Caddy
Caddy --> Vue
Caddy -->|/api/*| FastAPI
Caddy -->|/ws| WebSocket
FastAPI --> Services
WebSocket --> Services
Services --> Core
ScraperSvc --> TMDBSvc
ScraperSvc --> ParserSvc
ScraperSvc --> NFOSvc
ScraperSvc --> ImageSvc
ScraperSvc --> RenameSvc
ScraperSvc --> P115Svc
TMDBSvc --> TMDB
Services --> Emby
P115Svc --> P115
WatcherSvc --> P115Svc
Loading
graph LR
subgraph Orchestration["编排层"]
Scraper[ScraperService]
end
subgraph Mixins["Mixin 模式"]
Config[ScraperConfigMixin<br/>配置管理]
Metadata[ScraperMetadataMixin<br/>元数据处理]
Media[ScraperMediaMixin<br/>媒体文件处理]
end
subgraph CoreServices["核心服务"]
Parser[ParserService]
TMDB[TMDBService]
NFO[NFOService]
Image[ImageService]
Rename[RenameService]
Subtitle[SubtitleService]
P115[P115Service<br/>115 网盘适配]
end
Scraper --> Config
Scraper --> Metadata
Scraper --> Media
Config --> Parser
Metadata --> TMDB
Metadata --> NFO
Media --> Image
Media --> Subtitle
Media --> Rename
Media --> P115
Loading
flowchart TD
Start([开始]) --> Scan[扫描文件夹]
Scan --> Filter{文件过滤}
Filter -->|通过| Parse[解析文件名]
Filter -->|过滤| Skip[跳过文件]
Parse --> Extract[提取剧名/季/集]
Extract --> Search[搜索 TMDB]
Search --> Match{匹配结果}
Match -->|自动匹配| GetDetails[获取详情]
Match -->|需要选择| Manual[手动选择]
Match -->|无结果| Failed[标记失败]
Manual --> GetDetails
GetDetails --> GenNFO[生成 NFO]
GenNFO --> Organize[文件整理]
Organize --> Mode{整理模式}
Mode -->|复制| Copy[复制文件]
Mode -->|移动| Move[移动文件]
Mode -->|硬链接| HardLink[创建硬链接]
Mode -->|软链接| SymLink[创建软链接]
Copy --> Download[下载图片]
Move --> Download
HardLink --> Download
SymLink --> Download
Download --> Subtitle[处理字幕]
Subtitle --> Record[记录历史]
Record --> Success([完成])
Failed --> Record
Skip --> End([结束])
Loading
flowchart LR
Input[原始文件名] --> Clean[清理垃圾信息]
Clean --> Detect{检测格式}
Detect -->|S01E01| Standard[标准解析器]
Detect -->|第x集| Chinese[中文解析器]
Detect -->|第x話| Japanese[日文解析器]
Standard --> Extract[提取信息]
Chinese --> Extract
Japanese --> Extract
Extract --> Output[剧名 + 季号 + 集号]
Loading
sequenceDiagram
participant User as 用户
participant API as API 层
participant Queue as 任务队列
participant Worker as 工作进程
participant WS as WebSocket
User->>API: 创建刮削任务
API->>Queue: 添加到队列
API-->>User: 返回任务 ID
Queue->>Worker: 分发任务
Worker->>WS: 推送进度
WS-->>User: 实时更新
Worker->>Worker: 执行刮削
Worker->>WS: 推送结果
WS-->>User: 显示结果
Loading
MHTI/
├── 📂 server/ # Python 后端
│ ├── 📂 api/ # API 路由层
│ │ ├── auth.py # 认证接口
│ │ ├── files.py # 文件操作
│ │ ├── scraper.py # 刮削接口
│ │ ├── config.py # 配置管理
│ │ ├── tmdb.py # TMDB 代理
│ │ ├── watcher.py # 文件监控
│ │ └── websocket.py # WebSocket
│ ├── 📂 core/ # 核心层
│ │ ├── container.py # 依赖注入容器
│ │ ├── database.py # 数据库连接
│ │ ├── auth.py # 认证逻辑
│ │ ├── middleware.py # 中间件
│ │ └── 📂 db/ # 数据库模块
│ │ ├── connection.py # 连接池
│ │ └── schema.py # 表结构
│ ├── 📂 services/ # 业务服务层
│ │ ├── scraper_service.py # 刮削编排器
│ │ ├── tmdb_service.py # TMDB 服务
│ │ ├── parser_service.py # 解析服务
│ │ ├── nfo_service.py # NFO 生成
│ │ ├── image_service.py # 图片下载
│ │ ├── rename_service.py # 文件整理
│ │ ├── p115_service.py # 115 网盘服务
│ │ ├── watcher_service.py # 文件监控(本地 + 115)
│ │ ├── scheduler_service.py # 定时任务
│ │ └── 📂 parsers/ # 解析器集合
│ │ ├── episode_standard.py
│ │ ├── episode_chinese.py
│ │ └── episode_japanese.py
│ ├── 📂 models/ # 数据模型
│ │ ├── scraper.py # 刮削模型
│ │ ├── tmdb.py # TMDB 模型
│ │ ├── file.py # 文件模型
│ │ ├── cloud_115.py # 115 网盘模型
│ │ ├── storage.py # 存储定位模型
│ │ └── ...
│ └── 📂 tests/ # 单元测试
├── 📂 web/ # Vue.js 前端
│ ├── 📂 src/
│ │ ├── 📂 api/ # API 客户端
│ │ ├── 📂 views/ # 页面视图
│ │ │ ├── HomePage.vue # 首页
│ │ │ ├── ScanPage.vue # 手动任务
│ │ │ ├── HistoryPage.vue # 刮削记录
│ │ │ ├── FilesPage.vue # 文件管理
│ │ │ └── SettingsPage.vue # 设置页面
│ │ ├── 📂 components/ # 组件库
│ │ │ ├── 📂 common/ # 通用组件
│ │ │ ├── 📂 layout/ # 布局组件
│ │ │ ├── 📂 scan/ # 扫描组件
│ │ │ ├── 📂 scrape/ # 刮削组件
│ │ │ └── 📂 settings/ # 设置组件
│ │ ├── 📂 stores/ # Pinia 状态
│ │ │ ├── auth.ts # 认证状态
│ │ │ ├── scraper.ts # 刮削状态
│ │ │ └── theme.ts # 主题状态
│ │ ├── 📂 composables/ # 组合式函数
│ │ ├── 📂 utils/ # 工具函数
│ │ └── 📂 router/ # 路由配置
│ └── package.json
├── 📂 data/ # 数据目录
│ └── scraper.db # SQLite 数据库
├── docker-compose.yml # Docker 编排
├── Dockerfile # 多阶段构建
├── Caddyfile # Caddy 配置
└── pyproject.toml # Python 依赖
# 克隆仓库
git clone https://github.com/your-username/mhti.git
cd mhti
# 启动服务
docker-compose up -d
# 查看日志
docker-compose logs -f
# 访问应用
# 主页: http://localhost:8000
# API 文档: http://localhost:8000/api/docs
version : ' 3.8'
services :
mhti :
image : xiyan520/mhti:latest
container_name : mhti
restart : unless-stopped
ports :
- " 8000:8000" # 主入口
volumes :
- ./data:/app/data # 数据持久化
- /path/to/media:/media:ro # 媒体库(只读)
- /path/to/output:/output # 输出目录
environment :
- TZ=Asia/Shanghai
- DATA_DIR=/app/data
# 后端开发(方案 A:虚拟环境)
python -m venv .venv
# Windows
.\. venv\S cripts\a ctivate
# macOS / Linux
source .venv/bin/activate
python -m pip install -r requirements.txt
python run_server.py --host 0.0.0.0 --port 8000 --reload
# 后端开发(方案 B:不使用虚拟环境)
python -m pip install --target .local_packages -r requirements.txt
python run_server.py --host 0.0.0.0 --port 8000 --reload
# 前端开发
cd web
npm install
npm run dev
说明:
方案 A 使用当前激活的虚拟环境。
方案 B 会把后端依赖安装到仓库根目录 .local_packages/,不需要创建或激活虚拟环境。
run_server.py 会优先使用当前 Python 环境;若当前环境缺依赖,再回退到 .local_packages/。
为兼容早期说明,若仓库里已经存在 .python_packages/,启动脚本也会继续尝试它。
若只需本机访问,后端可改用 --host 127.0.0.1。
方法
路径
说明
POST
/login
用户登录
POST
/logout
用户登出
POST
/register
注册账户
POST
/refresh
刷新令牌
GET
/status
认证状态
GET
/sessions
会话列表
方法
路径
说明
POST
/scan
扫描文件夹
GET
/browse
浏览目录
方法
路径
说明
POST
/scrape
执行刮削
POST
/scrape-by-id
按 TMDB ID 刮削
GET
/status
刮削状态
方法
路径
说明
GET/PUT
/tmdb
TMDB 配置
GET/PUT
/proxy
代理设置
GET/PUT
/organize
整理配置
GET/PUT
/download
下载设置
GET/PUT
/nfo
NFO 设置
GET
/115
115 登录状态
GET
/115/devices
115 登录设备列表
POST
/115/login/qrcode
115 扫码登录
GET
/115/login/status
115 登录状态轮询
DELETE
/115/login
115 退出登录
路径
说明
/api/tmdb/*
TMDB 代理接口
/api/emby/*
Emby 集成
/api/watcher/*
文件夹监控(本地 + 115)
/api/history/*
历史记录
/api/manual-jobs/*
手动任务管理
/api/scheduler/*
定时任务
/ws
WebSocket 实时通信
/health
健康检查
路径
页面
功能
/
首页
统计概览、快捷入口
/login
登录
用户认证
/scan
手动任务
创建刮削任务
/history
刮削记录
查看历史记录
/files
文件管理
浏览媒体文件
/settings
设置
系统配置(含 115 网盘登录)
/security
安全设置
账户管理
技术
版本
用途
Python
3.11+
运行时
FastAPI
0.109+
Web 框架
Uvicorn
0.27+
ASGI 服务器
aiosqlite
0.19+
异步 SQLite
httpx
0.27+
HTTP 客户端
watchdog
4.0+
文件监控
python-jose
3.3+
JWT 认证
Pydantic
2.6+
数据验证
p115client
0.0.8.6.6
115 网盘客户端
技术
版本
用途
Vue
3.5+
前端框架
TypeScript
5.9+
类型系统
Vite
7+
构建工具
Pinia
3.0+
状态管理
Vue Router
4.6+
路由管理
Naive UI
2.43+
UI 组件库
Axios
1.13+
HTTP 客户端
技术
用途
Docker
容器化
Caddy
反向代理
SQLite
数据存储
erDiagram
config {
string key PK
text value
datetime updated_at
}
admin {
int id PK
string username UK
string password_hash
datetime created_at
}
sessions {
string id PK
int user_id FK
string token
datetime expires_at
datetime created_at
}
history_records {
string id PK
string file_path
string status
string tmdb_id
json details
datetime created_at
}
scraped_files {
string id PK
string source_path
string target_path
int file_size
int tmdb_id
int season
int episode
datetime scraped_at
}
manual_jobs {
int id PK
string name
string source_dir
string output_dir
string status
datetime created_at
}
scrape_jobs {
string id PK
string file_path
string status
int source_id FK
datetime created_at
}
watched_folders {
int id PK
string path
string output_dir
bool enabled
datetime created_at
}
admin ||--o{ sessions : has
manual_jobs ||--o{ scrape_jobs : contains
scrape_jobs ||--o| history_records : creates
history_records ||--o| scraped_files : records
Loading
模式
说明
适用场景
copy
复制文件
保留原文件
move
移动文件
节省空间
hardlink
硬链接
同分区节省空间(仅本地)
symlink
软链接
跨分区引用(仅本地)
功能
说明
扫码登录
在设置页扫码登录 115 网盘,cookies 加密存储
文件浏览
浏览 115 网盘目录,选择源/目标目录
115→115 整理
视频在 115 内整理(复制/移动+改名),NFO/图片留本地
115→本地整理
从 115 下载视频到本地后整理
监控模式
兼容模式(全量轮询)/ 事件模式(生活事件 API 增量监控)
TMDB 核验
整理前核验 TMDB 中季/集存在性,避免错误重命名
变量
默认值
说明
DATA_DIR
/app/data
数据目录
TZ
Asia/Shanghai
时区
# 运行所有测试
python -m pytest
# 运行覆盖率测试
python -m pytest --cov=server --cov-report=html
# 运行特定测试
python -m pytest server/tests/services/test_parser_service.py -v
Python : Ruff + Black (line-length=100)
TypeScript : ESLint + Prettier
类型注解 : 严格模式
语言
风格
Python
snake_case
TypeScript
camelCase
Vue 组件
PascalCase
<type>(<scope>): <description>
类型:
- feat: 新功能
- fix: 修复
- docs: 文档
- style: 格式
- refactor: 重构
- test: 测试
- chore: 构建/工具
本项目采用 MIT 许可证 - 详见 LICENSE 文件。
欢迎提交 Issue 和 Pull Request!
Fork 本仓库
创建特性分支 (git checkout -b feature/AmazingFeature)
提交更改 (git commit -m 'feat: Add some AmazingFeature')
推送到分支 (git push origin feature/AmazingFeature)
创建 Pull Request
Made with ❤️ for media enthusiasts