使用 Docker Compose 部署 fontInAss 字幕字体处理服务
你是否遇到过这样的情况:在 Emby 或 Jellyfin 上播放带有精美 ASS 字幕的动漫或电影时,字幕却显示为系统默认字体,完全失去了原有的视觉效果?这是因为字幕文件使用了设备上不存在的特殊字体(如方正字体、思源字体等),导致播放器只能回退到默认字体显示。
fontInAss 正是为解决这个问题而生的开源项目,它能够自动将字幕所需的字体嵌入到字幕文件中,确保在任何设备上都能正确显示特殊字体效果。本文将详细介绍如何使用 Docker Compose 部署 fontInAss 服务,并与 Emby/Jellyfin 无缝集成。但是注意,本项目的效果完全取决于你的字体库规模,如果只有很少的字体,那么可能无法正常显示/出现有的有字体有的无的难看情况。
本服不需要使用,因为大部分都已经我自己处理过字幕子集化。本文仅作学习用。
fontInAss 是什么?
fontInAss 是一个专为 Emby/Jellyfin 设计的字幕字体子集化和嵌入工具。它通过拦截播放器的字幕请求,实时提取字幕中使用的字体并嵌入到 ASS 格式字幕中,从而确保特殊字体能够正确显示。
对比参照


主要功能
- 实时字幕处理: 播放视频时自动拦截字幕请求,无需手动处理
- 字体子集化: 仅提取字幕实际使用的字形,大幅减小文件体积(从 10MB 压缩到 50KB)
- 双模式字体支持: 支持本地字体库 + 在线字体下载(可选)
- Web UI 批处理: 提供 Web 界面用于批量处理字幕文件
- 格式转换: 自动将 SRT 字幕转换为 ASS 格式并嵌入字体
- 智能匹配: 采用评分算法智能匹配字体名称、粗细、斜体等属性
工作原理
原始 ASS 字幕(100KB)├─ 字幕文本: "这是中文字幕"└─ 字体声明: Font: 思源黑体 CN Bold
↓ fontInAss 处理流程
1. 拦截字幕请求2. 分析字幕使用的所有字符3. 从字体库提取对应字形4. 压缩字体(10MB → 50KB)5. UUEncode 编码并嵌入字幕
↓
处理后的 ASS 字幕(150KB)├─ 字幕文本: "这是中文字幕"├─ 字体声明: Font: 思源黑体 CN Bold└─ [Fonts] 段: <嵌入的字体数据>架构设计
本文采用双轨模式部署,确保不影响现有的 Emby 服务:
路径 A(原有方式,保持不变):客户端 → http://localhost:8096 → Emby 服务器
路径 B(新增的字幕增强方式):客户端 → HTTPS (443) → Nginx 反向代理 ↓ 内部端口 8011 → fontInAss 容器 ↓ http://localhost:8096 → Emby 服务器优势:
- ✅ 原有 Emby 访问方式完全不受影响
- ✅ fontInAss 作为可选的增强功能
- ✅ 两种访问方式并存,随时切换
组件说明
| 组件 | 说明 |
|---|---|
| fontInAss 容器 | 使用 riderlty/fontinass:noproxy 镜像,监听 8011 端口 |
| Nginx 反向代理 | 处理 SSL 终止、字幕请求拦截、WebSocket 代理 |
| 本地字体库 | 存储 TTF/TTC/OTF 字体文件,支持自动监控和扫描 |
| Emby 服务器 | 现有的 Emby 服务,无需修改任何配置 |
部署准备
系统要求
- Linux 服务器(Debian/Ubuntu 推荐)
- Docker 和 Docker Compose
- Nginx(用于反向代理)
- 运行中的 Emby/Jellyfin 服务器
推荐配置
- 本地字体库(可选但强烈推荐,避免依赖网络)
- 域名和 SSL 证书(生产环境必需)
- 至少 2GB 内存和 10GB 磁盘空间
TIP如果你没有字体库,可以先使用在线字体模式部署,稍后再添加本地字体。本文示例使用本地字体库模式。
部署步骤
1. 创建工作目录
# 创建项目目录mkdir -p /root/docker_yaml/fontInAsscd /root/docker_yaml/fontInAss
# 创建必要的子目录mkdir -p fonts data logs目录说明:
fonts/: 存储本地字体文件(支持子目录)data/: 存储 SQLite 字体数据库logs/: 存储运行日志和字体缺失记录
2. 创建 Docker Compose 配置
创建 docker-compose.yml 文件:
version: '3.8'
services: fontinass: image: riderlty/fontinass:noproxy container_name: fontinass restart: unless-stopped ports: - "127.0.0.1:8011:8011" # 仅监听本地,不暴露到外网 environment: # Emby 服务器地址(容器内访问宿主机) EMBY_SERVER_URL: "http://host.docker.internal:8096" # Web 端字体渲染支持 EMBY_WEB_EMBED_FONT: "True" # 日志级别 LOG_LEVEL: "INFO" # 禁用在线字体,仅使用本地字体库 DISABLE_ONLINE_FONTS: "True" # 字体缓存配置 FONT_CACHE_SIZE: "50" FONT_CACHE_TTL: "60" # 字幕缓存配置 SUB_CACHE_SIZE: "50" SUB_CACHE_TTL: "60" SRT_2_ASS_FORMAT: "Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding" SRT_2_ASS_STYLE: "Style: Default,楷体,20,&H03FFFFFF,&H00FFFFFF,&H00000000,&H02000000,-1,0,0,0,100,100,0,0,1,2,0,2,10,10,10,1" volumes: - ./fonts:/fonts # 字体目录 - ./data:/data # 数据库目录 - ./logs:/logs # 日志目录 extra_hosts: # 允许容器访问宿主机的 Emby 服务 - "host.docker.internal:host-gateway"DISABLE_ONLINE_FONTS: "True" 配置禁用在线字体下载,完全使用本地字体库。如果你希望在本地字体缺失时自动从网络下载,可以设置为 "False"。
3. 配置 Nginx 反向代理
创建 Nginx 配置文件 /etc/nginx/sites-available/fontinass:
这是我的nginx,仅供参考。
# 上游服务器配置upstream fontinass_backend { server 127.0.0.1:8011; keepalive 32;}
upstream emby_backend { server 127.0.0.1:8096; keepalive 32;}
# HTTP 重定向到 HTTPSserver { listen 80; listen [::]:80; server_name your-domain.com;
# 重定向所有HTTP请求到HTTPS return 301 https://$host$request_uri;}
# HTTPS 主配置server { listen 443 ssl; listen [::]:443 ssl; http2 on; server_name your-domain.com;
# SSL 证书配置 ssl_certificate /path/to/cert.pem; ssl_certificate_key /path/to/key.pem;
# SSL 优化配置 ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384'; ssl_prefer_server_ciphers on; ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m;
# 安全头 add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; add_header X-Content-Type-Options "nosniff" always; add_header X-Frame-Options "SAMEORIGIN" always;
# 日志 access_log /var/log/nginx/fontinass.access.log; error_log /var/log/nginx/fontinass.error.log;
# 客户端上传大小限制 client_max_body_size 100M;
# WebSocket 支持(直接转发到 Emby) location ~ /(socket|embywebsocket) { proxy_pass http://emby_backend; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_read_timeout 86400; }
# 字幕文件拦截(转发到 fontInAss 处理) location ~* /videos/(.*)/Subtitles/(.*)/(Stream\.ass|Stream\.ssa|Stream\.srt|Stream\.)$ { proxy_pass http://fontinass_backend; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_read_timeout 300; proxy_connect_timeout 75;
# Gzip 压缩(针对字幕文件) gzip on; gzip_comp_level 6; gzip_types text/x-ssa text/plain application/x-subrip; }
# 飞牛/Jellyfin 字幕 API(转发到 fontInAss) location ~ /v/api/v1/subtitle/dl/(.*) { proxy_pass http://fontinass_backend; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; }
# JS 文件修改(Web 端字体渲染支持) location ~ /web/modules/htmlvideoplayer/plugin\.js { proxy_pass http://fontinass_backend; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_cache_bypass 1; add_header Content-Type "application/javascript" always; }
location ~ /web/bower_components/(.*)/subtitles-octopus\.js { proxy_pass http://fontinass_backend; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_cache_bypass 1; add_header Content-Type "application/javascript" always; }
# fontInAss Web UI 和 API location ~ ^/(subset|api|color|fontinass)/ { proxy_pass http://fontinass_backend; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; }
# 默认转发到 Emby 服务器 location / { proxy_pass http://emby_backend; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Host $host;
# 缓冲配置 proxy_buffering off; proxy_redirect off; }}启用 Nginx 配置:
# 创建软链接启用配置ln -s /etc/nginx/sites-available/fontinass /etc/nginx/sites-enabled/
# 测试配置nginx -t
# 重载 Nginxsystemctl reload nginx4. 启动 fontInAss 服务
cd /root/docker_yaml/fontInAss
# 启动容器docker compose up -d
# 查看日志确认启动成功docker compose logs -f fontinass正常启动的日志输出:
🤖 INFO 本地字体文件夹:/fonts🤖 INFO 开始检查数据库与目录的一致性...🤖 INFO 监控中:/fonts🌏 INFO Started server process [8]🌏 INFO Waiting for application startup.🌏 INFO Application startup complete.🌏 INFO Uvicorn running on http://0.0.0.0:8011
字体库配置
添加本地字体
fontInAss 支持自动监控 fonts 目录,添加字体后会自动扫描并添加到数据库。
注意:本项目的可用程度完全取决于你的字体库的规模。如果只有很少的字体,那么可能无法正常显示/出现有的有字体有的无的难看情况。
# 复制字体文件到字体目录cp /path/to/your/*.ttf /root/docker_yaml/fontInAss/fonts/
# 或创建子目录分类管理mkdir -p fonts/中文字体 fonts/日文字体 fonts/英文字体cp SourceHanSans*.ttf fonts/中文字体/支持的字体格式:
.ttf(TrueType Font).ttc(TrueType Collection).otf(OpenType Font)
字体自动识别流程
1. watchdog 实时监控 /fonts 目录2. 发现新字体 → 提取元信息 - 字体族名(familyName) - 完整名称(fullName) - PostScript 名称 - 粗细(weight) - 样式(bold/italic)3. 添加到 SQLite 数据库4. 立即可用(无需重启容器)查看字体统计:
# 查看字体文件数量find /root/docker_yaml/fontInAss/fonts -type f \( -name "*.ttf" -o -name "*.ttc" -o -name "*.otf" \) | wc -l
# 查看字体目录占用空间du -sh /root/docker_yaml/fontInAss/fonts验证部署
1. 检查容器状态
# 查看容器运行状态docker compose ps
# 应该显示 fontinass 容器状态为 "Up"2. 测试本地 API
# 测试 fontInAss APIcurl -I http://localhost:8011/subset/
# 应该返回 HTTP/1.1 200 OK
3. 测试 Nginx 代理
# 测试代理是否工作curl -I https://your-domain.com/subset/
# 应该返回 200 OK 并显示 fontInAss Web UI
客户端配置
双轨访问模式
fontInAss 采用双轨模式,不影响现有的 Emby 使用习惯:
| 访问方式 | 地址 | 用途 |
|---|---|---|
| 方式 A(原有) | http://localhost:8096 | 日常观看,不处理字幕 |
| 方式 B(新增) | https://your-domain.com | 字幕字体增强,自动处理特殊字体 |
配置步骤
大多数 Emby 客户端支持多服务器配置:
-
保留原有服务器配置(不改动)
-
添加新服务器:
- 打开 Emby 客户端设置
- 添加新服务器:
https://your-domain.com - 使用相同的账号登录
-
切换使用:
- 需要字幕字体增强时,使用新地址
- 日常观看使用原地址
Web UI 使用
fontInAss 提供了 Web UI 用于批量处理字幕文件。
访问地址
https://your-domain.com/subset/
使用流程
1. 访问 Web UI2. 上传字幕文件(支持拖拽)3. 等待处理(通常几秒钟)4. 下载带字体的字幕文件5. 替换原字幕使用NOTEWeb UI 适合批量预处理字幕库,或在非 Emby 播放器上使用的字幕文件。日常通过 Emby 观看时,字幕会自动处理,无需手动使用 Web UI。
常见问题
Q1: 字幕不显示字体效果?
可能原因和解决方案:
- 字体库中没有所需字体
Terminal window # 查看容器日志,确认缺失的字体docker compose logs -f fontinass | grep "缺失"# 添加缺失的字体到 fonts 目录cp missing-font.ttf /root/docker_yaml/fontInAss/fonts/
Q2: 如何切换回在线字体模式?
如果你发现本地字体库不完整,可以启用在线字体下载作为补充:
我查了代码,应该是部署存了一份XZ的字体包在123网盘。

environment: DISABLE_ONLINE_FONTS: "True" # 禁用在线字体 DISABLE_ONLINE_FONTS: "False" # 启用在线字体修改后重启容器:
docker compose downdocker compose up -d在线字体会自动下载到 fonts/download/ 目录。
Q3: 如何查看字幕处理日志?
fontInAss 提供详细的日志记录:
# 实时查看容器日志docker compose logs -f fontinass
# 查看缺失字体记录cat /root/docker_yaml/fontInAss/logs/miss_logs.txt
# 查看 Nginx 访问日志tail -f /var/log/nginx/fontinass.access.log
性能优化
字体缓存配置
fontInAss 使用三级缓存策略:内存缓存 → 本地数据库 → 在线数据库。
environment: FONT_CACHE_SIZE: "50" # 字体缓存数量(可根据内存调整) FONT_CACHE_TTL: "60" # 字体缓存过期时间(分钟)
SUB_CACHE_SIZE: "50" # 字幕缓存数量 SUB_CACHE_TTL: "60" # 字幕缓存过期时间(分钟)建议配置:
- 内存充足(8GB+):
FONT_CACHE_SIZE: "100" - 内存有限(2-4GB):
FONT_CACHE_SIZE: "30"
Nginx 优化
如果你的用户量较大,可以启用 Nginx 缓存:
# 在 http 块中添加proxy_cache_path /var/cache/nginx/fontinass levels=1:2 keys_zone=fontinass_cache:10m max_size=1g inactive=60m;
# 在 location ~ /videos/.*/Subtitles/ 块中添加proxy_cache fontinass_cache;proxy_cache_valid 200 60m;proxy_cache_key "$scheme$request_method$host$request_uri";维护操作
日常维护
# 查看运行状态docker compose ps
# 查看日志docker compose logs --tail=100 fontinass
# 重启服务docker compose restart fontinass
# 更新镜像docker compose pulldocker compose up -d备份重要数据
# 备份字体数据库和配置tar -czf fontinass-backup-$(date +%Y%m%d).tar.gz \ docker-compose.yml \ data/ \ fonts/清理缓存
# 清理 Docker 缓存docker system prune -a
# 清理 Nginx 缓存(如果启用)rm -rf /var/cache/nginx/fontinass/*总结
fontInAss 通过智能的字体子集化和嵌入技术,完美解决了 Emby/Jellyfin 特殊字体字幕显示问题。本文介绍的双轨部署模式,既保留了原有服务的稳定性,又提供了字幕字体增强功能,是一个适合懒人的解决方案。
适用场景
- 观看带有特殊字体的动漫字幕
- 在移动设备上正确显示字幕效果
- 字幕组制作和分发带字体的字幕
- 家庭媒体中心字幕优化
希望本文能帮助你顺利部署 fontInAss 服务,享受完美的字幕观看体验!