3094 字
15 分钟

使用 Docker Compose 部署 fontInAss 字幕字体处理服务

你是否遇到过这样的情况:在 Emby 或 Jellyfin 上播放带有精美 ASS 字幕的动漫或电影时,字幕却显示为系统默认字体,完全失去了原有的视觉效果?这是因为字幕文件使用了设备上不存在的特殊字体(如方正字体、思源字体等),导致播放器只能回退到默认字体显示。

fontInAss 正是为解决这个问题而生的开源项目,它能够自动将字幕所需的字体嵌入到字幕文件中,确保在任何设备上都能正确显示特殊字体效果。本文将详细介绍如何使用 Docker Compose 部署 fontInAss 服务,并与 Emby/Jellyfin 无缝集成。但是注意,本项目的效果完全取决于你的字体库规模,如果只有很少的字体,那么可能无法正常显示/出现有的有字体有的无的难看情况。

本服不需要使用,因为大部分都已经我自己处理过字幕子集化。本文仅作学习用。

fontInAss 是什么?#

RiderLty
/
fontInAss
Waiting for api.github.com...
00K
0K
0K
Waiting...

fontInAss 是一个专为 Emby/Jellyfin 设计的字幕字体子集化和嵌入工具。它通过拦截播放器的字幕请求,实时提取字幕中使用的字体并嵌入到 ASS 格式字幕中,从而确保特殊字体能够正确显示。

对比参照#

image-20260112201306301

image-20260112201318797

主要功能#

  • 实时字幕处理: 播放视频时自动拦截字幕请求,无需手动处理
  • 字体子集化: 仅提取字幕实际使用的字形,大幅减小文件体积(从 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. 创建工作目录#

Terminal window
# 创建项目目录
mkdir -p /root/docker_yaml/fontInAss
cd /root/docker_yaml/fontInAss
# 创建必要的子目录
mkdir -p fonts data logs

目录说明:

  • fonts/: 存储本地字体文件(支持子目录)
  • data/: 存储 SQLite 字体数据库
  • logs/: 存储运行日志和字体缺失记录

2. 创建 Docker Compose 配置#

创建 docker-compose.yml 文件:

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 重定向到 HTTPS
server {
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 配置:

Terminal window
# 创建软链接启用配置
ln -s /etc/nginx/sites-available/fontinass /etc/nginx/sites-enabled/
# 测试配置
nginx -t
# 重载 Nginx
systemctl reload nginx

4. 启动 fontInAss 服务#

Terminal window
cd /root/docker_yaml/fontInAss
# 启动容器
docker compose up -d
# 查看日志确认启动成功
docker compose logs -f fontinass

正常启动的日志输出:

Terminal window
🤖 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

image-20260112194828646

字体库配置#

添加本地字体#

fontInAss 支持自动监控 fonts 目录,添加字体后会自动扫描并添加到数据库。

字体下载:https://pan.acgrip.com/

注意:本项目的可用程度完全取决于你的字体库的规模。如果只有很少的字体,那么可能无法正常显示/出现有的有字体有的无的难看情况。

Terminal window
# 复制字体文件到字体目录
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. 立即可用(无需重启容器)

查看字体统计:

Terminal window
# 查看字体文件数量
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. 检查容器状态#

Terminal window
# 查看容器运行状态
docker compose ps
# 应该显示 fontinass 容器状态为 "Up"

2. 测试本地 API#

Terminal window
# 测试 fontInAss API
curl -I http://localhost:8011/subset/
# 应该返回 HTTP/1.1 200 OK
![image-20260112164358436](https://s3.catcat.blog/images/2026/01/20260112164358682.avif)

3. 测试 Nginx 代理#

Terminal window
# 测试代理是否工作
curl -I https://your-domain.com/subset/
# 应该返回 200 OK 并显示 fontInAss Web UI
![image-20260112162104129](https://s3.catcat.blog/images/2026/01/20260112162133271.avif)

客户端配置#

双轨访问模式#

fontInAss 采用双轨模式,不影响现有的 Emby 使用习惯:

访问方式地址用途
方式 A(原有)http://localhost:8096日常观看,不处理字幕
方式 B(新增)https://your-domain.com字幕字体增强,自动处理特殊字体

配置步骤#

大多数 Emby 客户端支持多服务器配置:

  1. 保留原有服务器配置(不改动)

  2. 添加新服务器

    • 打开 Emby 客户端设置
    • 添加新服务器:https://your-domain.com
    • 使用相同的账号登录
  3. 切换使用

    • 需要字幕字体增强时,使用新地址
    • 日常观看使用原地址

Web UI 使用#

fontInAss 提供了 Web UI 用于批量处理字幕文件。

访问地址#

https://your-domain.com/subset/

image-20260112162104129

使用流程#

1. 访问 Web UI
2. 上传字幕文件(支持拖拽)
3. 等待处理(通常几秒钟)
4. 下载带字体的字幕文件
5. 替换原字幕使用
NOTE

Web UI 适合批量预处理字幕库,或在非 Emby 播放器上使用的字幕文件。日常通过 Emby 观看时,字幕会自动处理,无需手动使用 Web UI。

常见问题#

Q1: 字幕不显示字体效果?#

可能原因和解决方案:

  1. 字体库中没有所需字体
    Terminal window
    # 查看容器日志,确认缺失的字体
    docker compose logs -f fontinass | grep "缺失"
    # 添加缺失的字体到 fonts 目录
    cp missing-font.ttf /root/docker_yaml/fontInAss/fonts/

Q2: 如何切换回在线字体模式?#

如果你发现本地字体库不完整,可以启用在线字体下载作为补充:

我查了代码,应该是部署存了一份XZ的字体包在123网盘。

image-20260112162515483

docker-compose.yml
environment:
DISABLE_ONLINE_FONTS: "True" # 禁用在线字体
DISABLE_ONLINE_FONTS: "False" # 启用在线字体

修改后重启容器:

Terminal window
docker compose down
docker compose up -d

在线字体会自动下载到 fonts/download/ 目录。

Q3: 如何查看字幕处理日志?#

fontInAss 提供详细的日志记录:

Terminal window
# 实时查看容器日志
docker compose logs -f fontinass
# 查看缺失字体记录
cat /root/docker_yaml/fontInAss/logs/miss_logs.txt
# 查看 Nginx 访问日志
tail -f /var/log/nginx/fontinass.access.log

image-20260112194939138

性能优化#

字体缓存配置#

fontInAss 使用三级缓存策略:内存缓存 → 本地数据库 → 在线数据库。

docker-compose.yml
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";

维护操作#

日常维护#

Terminal window
# 查看运行状态
docker compose ps
# 查看日志
docker compose logs --tail=100 fontinass
# 重启服务
docker compose restart fontinass
# 更新镜像
docker compose pull
docker compose up -d

备份重要数据#

Terminal window
# 备份字体数据库和配置
tar -czf fontinass-backup-$(date +%Y%m%d).tar.gz \
docker-compose.yml \
data/ \
fonts/

清理缓存#

Terminal window
# 清理 Docker 缓存
docker system prune -a
# 清理 Nginx 缓存(如果启用)
rm -rf /var/cache/nginx/fontinass/*

总结#

fontInAss 通过智能的字体子集化和嵌入技术,完美解决了 Emby/Jellyfin 特殊字体字幕显示问题。本文介绍的双轨部署模式,既保留了原有服务的稳定性,又提供了字幕字体增强功能,是一个适合懒人的解决方案。

适用场景#

  • 观看带有特殊字体的动漫字幕
  • 在移动设备上正确显示字幕效果
  • 字幕组制作和分发带字体的字幕
  • 家庭媒体中心字幕优化

希望本文能帮助你顺利部署 fontInAss 服务,享受完美的字幕观看体验!

使用 Docker Compose 部署 fontInAss 字幕字体处理服务
https://catcat.blog/2026/01/deploy-fontinass-emby-subtitle-font
作者
猫猫博客
发布于
2026-01-12
许可协议
CC BY-NC-SA 4.0