320 lines
10 KiB
Markdown
320 lines
10 KiB
Markdown
|
|
# 开源影视媒体库自动化刮削整理完整技术方案(可落地)
|
|||
|
|
|
|||
|
|
## 一、方案概述
|
|||
|
|
|
|||
|
|
本方案针对个人/NAS影视媒体库(适配 Jellyfin/Emby/Kodi),基于**全开源工具栈**搭建一套标准化、可自动化、可API对接的媒体处理流水线,覆盖:文件标准化重命名、批量字幕下载、影视元数据刮削、NFO/海报/背景图生成、程序API自动化控制。
|
|||
|
|
|
|||
|
|
方案区分两套核心模式:
|
|||
|
|
|
|||
|
|
- **GUI手动精准刮削模式**:轻量化、低占用,替代TinyMediaManager
|
|||
|
|
|
|||
|
|
- **API全自动流水线模式**:支持脚本/自研系统对接,无人值守批量处理媒体库
|
|||
|
|
|
|||
|
|
适用场景:本地影视库、NAS媒体库、自建影音服务、个人媒体自动化运维。
|
|||
|
|
|
|||
|
|
## 二、核心工具选型对比(开源、无付费、无广告)
|
|||
|
|
|
|||
|
|
摒弃闭源工具,全部采用开源可商用工具,精准分工,避免单一工具短板。
|
|||
|
|
|
|||
|
|
|工具|核心用途|优势|短板|场景定位|
|
|||
|
|
|---|---|---|---|---|
|
|||
|
|
|MediaElch|GUI可视化刮削、生成标准NFO/海报|轻量快速、无Java依赖、中文适配、Kodi标准NFO、跨平台|无字幕下载、无API、新版无TVDB、动漫弱|手动精准刮削、替代TMM日常使用|
|
|||
|
|
|mnamer|批量文件标准化重命名(CLI)|开源跨平台、递归扫描、智能匹配、可脚本自动化|不生成NFO、不下载图片|媒体库前置规整,统一文件命名规范|
|
|||
|
|
|Subliminal|批量简体中文字幕下载(CLI)|开源批量、自动去重、适配主流视频格式|部分字幕源需网络优化|配套MediaElch补齐字幕能力|
|
|||
|
|
|SubtitleEdit|字幕修复、编码转换、时间轴校准|全能开源字幕工具、批量处理、解决乱码|无自动下载能力|字幕后置修复优化|
|
|||
|
|
|tinyMediaManager\(TMM\)|可视化刮削 \+ **完整REST API**|双源TMDB/TVDB、支持API远程控制、生态成熟、剧集识别强|Java占用高、启动慢|API自动化核心工具、老剧/剧集优先|
|
|||
|
|
|自建FastAPI刮削服务|自研无状态刮削API|完全自主可控、可深度定制、无程序依赖|需自行开发文件写入逻辑|自研系统对接、个性化流水线|
|
|||
|
|
|Radarr/Sonarr|全自动化媒体运维(下载\+刮削\+整理)|Docker友好、API完善、全自动无人值守|功能过重,单纯存量库刮削没必要|PT自动追更、全自动媒体库|
|
|||
|
|
|
|||
|
|
## 三、标准化媒体库目录规范(核心基础)
|
|||
|
|
|
|||
|
|
所有刮削工具生效的前提,统一文件夹结构,兼容所有影音服务器。
|
|||
|
|
|
|||
|
|
### 3\.1 电影目录规范
|
|||
|
|
|
|||
|
|
```Plain Text
|
|||
|
|
Media/
|
|||
|
|
└── Movies/
|
|||
|
|
└── 流浪地球 (2019)/ # 单电影独立文件夹
|
|||
|
|
└── 流浪地球 (2019).mkv # 标准化命名
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3\.2 剧集目录规范
|
|||
|
|
|
|||
|
|
```Plain Text
|
|||
|
|
Media/
|
|||
|
|
└── Shows/
|
|||
|
|
└── 漫长的季节 (2023)/
|
|||
|
|
├── Season 01/
|
|||
|
|
│ ├── S01E01.mkv
|
|||
|
|
│ └── S01E02.mkv
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3\.3 输出文件规范
|
|||
|
|
|
|||
|
|
- 电影元数据:`movie.nfo`
|
|||
|
|
|
|||
|
|
- 剧集元数据:`tvshow.nfo` \+ `episode.nfo`
|
|||
|
|
|
|||
|
|
- 图片资源:`poster.jpg`(海报)、`fanart.jpg`(背景)
|
|||
|
|
|
|||
|
|
- 字幕文件:视频同目录 `.srt` 简体中文字幕
|
|||
|
|
|
|||
|
|
## 四、方案一:轻量化手动刮削流水线(日常主力)
|
|||
|
|
|
|||
|
|
**适用人群**:不想装Java、追求流畅、手动精修媒体库、存量影片整理
|
|||
|
|
|
|||
|
|
**工具组合**:mnamer \+ Subliminal \+ MediaElch \+ SubtitleEdit
|
|||
|
|
|
|||
|
|
**执行顺序(固定流水线)**
|
|||
|
|
|
|||
|
|
### 4\.1 第一步:mnamer 文件标准化重命名
|
|||
|
|
|
|||
|
|
先规整杂乱文件名,为字幕匹配、元数据刮削打底。
|
|||
|
|
|
|||
|
|
核心配置文件 `.mnamer-v2.json`:
|
|||
|
|
|
|||
|
|
```Plain Text
|
|||
|
|
{
|
|||
|
|
"language": "zh-CN",
|
|||
|
|
"movie_api": "tmdb",
|
|||
|
|
"movie_format": "{name} ({year}).{extension}",
|
|||
|
|
"recurse": true,
|
|||
|
|
"extension_mask": ["mkv","mp4","mov","webm","ts","m4v"],
|
|||
|
|
"max_hits": 5
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
执行命令(先预览后生效,规避误改):
|
|||
|
|
|
|||
|
|
```Plain Text
|
|||
|
|
# 预览模式(无修改)
|
|||
|
|
mnamer --test 媒体目录路径
|
|||
|
|
# 正式重命名
|
|||
|
|
mnamer 媒体目录路径
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4\.2 第二步:Subliminal 批量下载中文字幕
|
|||
|
|
|
|||
|
|
```Plain Text
|
|||
|
|
# 递归下载简体中文字幕
|
|||
|
|
subliminal download -l zh 媒体目录路径
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4\.3 第三步:MediaElch 可视化精准刮削
|
|||
|
|
|
|||
|
|
核心预设配置(中文兼容最优):
|
|||
|
|
|
|||
|
|
- 数据源:TMDB,语言 `zh-CN`
|
|||
|
|
|
|||
|
|
- 开启:标题、简介、年份、评分、演员、海报、背景图下载
|
|||
|
|
|
|||
|
|
- 输出:标准Kodi NFO,适配Jellyfin/Emby/Kodi
|
|||
|
|
|
|||
|
|
- 自动清理旧冗余NFO、图片文件
|
|||
|
|
|
|||
|
|
### 4\.4 第四步:SubtitleEdit 字幕修复
|
|||
|
|
|
|||
|
|
批量解决字幕乱码、时间轴错位、编码不统一问题,统一转为UTF\-8编码。
|
|||
|
|
|
|||
|
|
## 五、方案二:API全自动无人值守流水线(进阶自动化)
|
|||
|
|
|
|||
|
|
**适用人群**:需要脚本控制、自研系统对接、NAS自动化、批量无人值守刮库
|
|||
|
|
|
|||
|
|
**两套API方案可选**:TMM官方API(开箱即用)、自建FastAPI(完全自研)
|
|||
|
|
|
|||
|
|
### 5\.1 方案2\.1:TMM REST API 自动化流水线(推荐商用落地)
|
|||
|
|
|
|||
|
|
#### 5\.1\.1 前置配置
|
|||
|
|
|
|||
|
|
- 开启TMM:设置\-系统\-API,启用服务,默认端口7878
|
|||
|
|
|
|||
|
|
- 获取API\-KEY,开启跨域访问
|
|||
|
|
|
|||
|
|
- API文档地址:`http://127.0.0.1:7878/api/docs`
|
|||
|
|
|
|||
|
|
#### 5\.1\.2 完整Python自动化脚本
|
|||
|
|
|
|||
|
|
```Plain Text
|
|||
|
|
import requests
|
|||
|
|
import time
|
|||
|
|
|
|||
|
|
# TMM配置
|
|||
|
|
TMM_HOST = "http://127.0.0.1:7878"
|
|||
|
|
API_KEY = "你的TMM_API_KEY"
|
|||
|
|
HEADERS = {"api-key": API_KEY}
|
|||
|
|
|
|||
|
|
# 扫描媒体库
|
|||
|
|
def scan_library(library_id: int):
|
|||
|
|
resp = requests.post(f"{TMM_HOST}/api/v1/library/scan/{library_id}", headers=HEADERS)
|
|||
|
|
print("库扫描完成:", resp.text)
|
|||
|
|
time.sleep(5)
|
|||
|
|
|
|||
|
|
# 单影片自动刮削(写NFO+下海报)
|
|||
|
|
def scrape_movie(movie_id: int):
|
|||
|
|
payload = {
|
|||
|
|
"scraper": "tmdb",
|
|||
|
|
"language": "zh-CN",
|
|||
|
|
"downloadImages": True,
|
|||
|
|
"writeNfo": True
|
|||
|
|
}
|
|||
|
|
resp = requests.post(f"{TMM_HOST}/api/v1/movies/scrape/{movie_id}", json=payload, headers=HEADERS)
|
|||
|
|
print("影片刮削完成:", resp.text)
|
|||
|
|
|
|||
|
|
# 获取库内所有影片
|
|||
|
|
def get_all_movies(library_id: int):
|
|||
|
|
resp = requests.get(f"{TMM_HOST}/api/v1/library/{library_id}/movies", headers=HEADERS)
|
|||
|
|
return resp.json()
|
|||
|
|
|
|||
|
|
if __name__ == "__main__":
|
|||
|
|
lib_id = 1 # 替换为你的媒体库ID
|
|||
|
|
scan_library(lib_id)
|
|||
|
|
movies = get_all_movies(lib_id)
|
|||
|
|
for movie in movies:
|
|||
|
|
scrape_movie(movie["id"])
|
|||
|
|
time.sleep(2)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 5\.2 方案2\.2:自建FastAPI无状态刮削服务(自研定制)
|
|||
|
|
|
|||
|
|
无第三方程序依赖,纯接口服务,可自由扩展NFO生成、图片下载、自定义规则。
|
|||
|
|
|
|||
|
|
#### 5\.2\.1 依赖安装
|
|||
|
|
|
|||
|
|
```Plain Text
|
|||
|
|
pip install fastapi uvicorn tmdbv3api pydantic
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 5\.2\.2 完整服务代码
|
|||
|
|
|
|||
|
|
```Plain Text
|
|||
|
|
from fastapi import FastAPI
|
|||
|
|
from pydantic import BaseModel
|
|||
|
|
from tmdbv3api import TMDb, Movie, TV
|
|||
|
|
import uvicorn
|
|||
|
|
|
|||
|
|
app = FastAPI(title="自研影视刮削API服务")
|
|||
|
|
|
|||
|
|
# TMDB配置
|
|||
|
|
tmdb = TMDb()
|
|||
|
|
tmdb.api_key = "你的TMDB_KEY"
|
|||
|
|
tmdb.language = "zh-CN"
|
|||
|
|
movie_api = Movie()
|
|||
|
|
tv_api = TV()
|
|||
|
|
|
|||
|
|
class SearchRequest(BaseModel):
|
|||
|
|
name: str
|
|||
|
|
year: int = None
|
|||
|
|
media_type: str
|
|||
|
|
|
|||
|
|
# 影视搜索刮削接口
|
|||
|
|
@app.post("/scrape/search")
|
|||
|
|
async def scrape_search(req: SearchRequest):
|
|||
|
|
if req.media_type == "movie":
|
|||
|
|
res = movie_api.search(req.name, year=req.year)
|
|||
|
|
elif req.media_type == "tv":
|
|||
|
|
res = tv_api.search(req.name, year=req.year)
|
|||
|
|
else:
|
|||
|
|
return {"error": "media_type仅支持movie/tv"}
|
|||
|
|
|
|||
|
|
result = []
|
|||
|
|
for item in res:
|
|||
|
|
result.append({
|
|||
|
|
"id": item.id,
|
|||
|
|
"title": item.title if req.media_type == "movie" else item.name,
|
|||
|
|
"original_title": item.original_title,
|
|||
|
|
"overview": item.overview,
|
|||
|
|
"release_date": getattr(item, "release_date", getattr(item, "first_air_date", "")),
|
|||
|
|
"poster_path": item.poster_path,
|
|||
|
|
"score": item.vote_average
|
|||
|
|
})
|
|||
|
|
return {"code":200, "data":result}
|
|||
|
|
|
|||
|
|
# 生成标准NFO文本工具函数
|
|||
|
|
def generate_movie_nfo(meta:dict) -> str:
|
|||
|
|
return f"""<movie>
|
|||
|
|
<title>{meta['title']}</title>
|
|||
|
|
<originaltitle>{meta['original_title']}</originaltitle>
|
|||
|
|
<plot>{meta['overview']}</plot>
|
|||
|
|
<year>{meta['release_date'][:4]}</year>
|
|||
|
|
<rating>{meta['score']}</rating>
|
|||
|
|
<tmdbid>{meta['id']}</tmdbid>
|
|||
|
|
</movie>"""
|
|||
|
|
|
|||
|
|
if __name__ == "__main__":
|
|||
|
|
uvicorn.run("main:app", host="0.0.0.0", port=8000)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
服务启动后,访问 `127.0.0.1:8000/docs` 可在线调试API。
|
|||
|
|
|
|||
|
|
## 六、Windows一键批量脚本(整合全流程)
|
|||
|
|
|
|||
|
|
双击即可完成:文件预览校验→正式重命名→批量字幕下载,全程可视化确认。
|
|||
|
|
|
|||
|
|
```Plain Text
|
|||
|
|
@echo off
|
|||
|
|
chcp 65001
|
|||
|
|
setlocal
|
|||
|
|
set "MEDIA_PATH=D:\Media\Movies"
|
|||
|
|
|
|||
|
|
echo ========== 第一步:预览文件重命名 ==========
|
|||
|
|
mnamer --test "%MEDIA_PATH%"
|
|||
|
|
set /p "choice=确认执行重命名?Y/N: "
|
|||
|
|
if /i not "%choice%"=="Y" exit
|
|||
|
|
|
|||
|
|
echo ========== 第二步:执行标准化重命名 ==========
|
|||
|
|
mnamer "%MEDIA_PATH%"
|
|||
|
|
|
|||
|
|
echo ========== 第三步:批量下载中文字幕 ==========
|
|||
|
|
subliminal download -l zh "%MEDIA_PATH%"
|
|||
|
|
|
|||
|
|
echo 全部任务执行完成!
|
|||
|
|
pause
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 七、场景化选型策略(核心落地指南)
|
|||
|
|
|
|||
|
|
### 7\.1 日常个人媒体库(首选)
|
|||
|
|
|
|||
|
|
mnamer \+ Subliminal \+ MediaElch,轻量无负担,中文适配最佳
|
|||
|
|
|
|||
|
|
### 7\.2 大量老剧集、海外剧集
|
|||
|
|
|
|||
|
|
改用 TMM,支持TVDB双源,识别准确率远超MediaElch
|
|||
|
|
|
|||
|
|
### 7\.3 需要程序自动化、系统对接
|
|||
|
|
|
|||
|
|
优先 TMM API(开箱即用),深度自研选择 FastAPI自建服务
|
|||
|
|
|
|||
|
|
### 7\.4 全自动PT追更媒体库(NAS)
|
|||
|
|
|
|||
|
|
Radarr \+ Sonarr 容器化部署,全流程无人值守
|
|||
|
|
|
|||
|
|
### 7\.5 大量动漫资源
|
|||
|
|
|
|||
|
|
补充开源工具 Mochi,支持Bangumi番剧数据源,弥补MediaElch短板
|
|||
|
|
|
|||
|
|
## 八、常见问题与解决方案(踩坑汇总)
|
|||
|
|
|
|||
|
|
- **TMDB刮削超时**:网络解析问题,优化hosts配置或合规代理
|
|||
|
|
|
|||
|
|
- **字幕命中率低**:必须先用mnamer标准化文件名,杂乱命名无法精准匹配
|
|||
|
|
|
|||
|
|
- **NFO不被Jellyfin识别**:文件统一UTF\-8编码、视频独立文件夹、禁止多层嵌套
|
|||
|
|
|
|||
|
|
- **MediaElch剧集匹配差**:新版无TVDB,老剧切换TMM处理
|
|||
|
|
|
|||
|
|
- **字幕乱码**:SubtitleEdit批量转为UTF\-8编码
|
|||
|
|
|
|||
|
|
## 九、方案优势总结
|
|||
|
|
|
|||
|
|
1. **全开源无版权风险**:所有工具均为开源协议,无付费、无捆绑、无水印
|
|||
|
|
|
|||
|
|
2. **分层适配场景**:兼顾手动精修 \+ 全自动API自动化,适配个人/自研系统/NAS
|
|||
|
|
|
|||
|
|
3. **标准化输出**:全部生成Kodi标准NFO,100%兼容Jellyfin/Emby/Kodi主流影音服务
|
|||
|
|
|
|||
|
|
4. **可扩展可定制**:支持自建API、二次开发、流水线自定义改造
|
|||
|
|
|
|||
|
|
> (注:部分内容可能由 AI 生成)
|