1951 字
10 分钟

Deploy fontInAss Subtitle Font Processing Service with Docker Compose

Have you ever encountered this situation: when playing anime or movies with beautiful ASS subtitles on Emby or Jellyfin, the subtitles display in the system default font, completely losing their original visual effect? This happens because the subtitle files use special fonts (such as FangZheng fonts, Source Han fonts, etc.) that don’t exist on the device, causing the player to fall back to default fonts.

fontInAss is an open-source project created specifically to solve this problem. It can automatically embed the fonts required by subtitles into the subtitle files, ensuring that special font effects display correctly on any device. This article will explain in detail how to deploy the fontInAss service using Docker Compose and integrate it seamlessly with Emby/Jellyfin. However, note that this project’s effectiveness depends entirely on the scale of your font library. If you only have a few fonts, it may not display properly or result in an ugly situation where some text has fonts and some doesn’t.

What is fontInAss?#

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

fontInAss is a subtitle font subsetting and embedding tool designed specifically for Emby/Jellyfin. It intercepts player subtitle requests in real-time, extracts the fonts used in the subtitles and embeds them into ASS format subtitles, ensuring that special fonts display correctly.

Main Features#

  • Real-time Subtitle Processing: Automatically intercepts subtitle requests during video playback, no manual processing needed
  • Font Subsetting: Extracts only the glyphs actually used in subtitles, significantly reducing file size (from 10MB compressed to 50KB)
  • Dual-mode Font Support: Supports local font library + online font download (optional)
  • Web UI Batch Processing: Provides a web interface for batch processing subtitle files
  • Format Conversion: Automatically converts SRT subtitles to ASS format and embeds fonts
  • Smart Matching: Uses scoring algorithm to intelligently match font names, weight, italic, and other attributes

How It Works#

Original ASS Subtitle (100KB)
├─ Subtitle text: "This is a subtitle"
└─ Font declaration: Font: Source Han Sans CN Bold
↓ fontInAss Processing Flow
1. Intercept subtitle request
2. Analyze all characters used in subtitle
3. Extract corresponding glyphs from font library
4. Compress font (10MB → 50KB)
5. UUEncode and embed into subtitle
Processed ASS Subtitle (150KB)
├─ Subtitle text: "This is a subtitle"
├─ Font declaration: Font: Source Han Sans CN Bold
└─ [Fonts] section: <embedded font data>

Architecture Design#

This article uses a dual-track deployment approach to ensure the existing Emby service is not affected:

Path A (Original method, unchanged):
Client → http://localhost:8096 → Emby Server
Path B (New subtitle enhancement method):
Client → HTTPS (443) → Nginx Reverse Proxy
Internal Port 8011 → fontInAss Container
http://localhost:8096 → Emby Server

Advantages:

  • ✅ Original Emby access method completely unaffected
  • ✅ fontInAss as an optional enhancement feature
  • ✅ Both access methods coexist, switch anytime

Component Description#

ComponentDescription
fontInAss ContainerUses riderlty/fontinass:noproxy image, listens on port 8011
Nginx Reverse ProxyHandles SSL termination, subtitle request interception, WebSocket proxy
Local Font LibraryStores TTF/TTC/OTF font files, supports automatic monitoring and scanning
Emby ServerExisting Emby service, no configuration changes needed

Deployment Preparation#

System Requirements#

  • Linux server (Debian/Ubuntu recommended)
  • Docker and Docker Compose
  • Nginx (for reverse proxy)
  • Running Emby/Jellyfin server
  • Local font library (optional but strongly recommended, avoids network dependency)
  • Domain name and SSL certificate (required for production environment)
  • At least 2GB memory and 10GB disk space
TIP

If you don’t have a font library, you can first deploy with online font mode and add local fonts later. This article uses local font library mode as an example.

Deployment Steps#

1. Create Working Directory#

Terminal window
# Create project directory
mkdir -p /root/docker_yaml/fontInAss
cd /root/docker_yaml/fontInAss
# Create necessary subdirectories
mkdir -p fonts data logs

Directory explanation:

  • fonts/: Stores local font files (supports subdirectories)
  • data/: Stores SQLite font database
  • logs/: Stores runtime logs and font missing records

2. Create Docker Compose Configuration#

Create docker-compose.yml file:

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" # Listen locally only, not exposed to external network
environment:
# Emby server address (container accessing host)
EMBY_SERVER_URL: "http://host.docker.internal:8096"
# Web font rendering support
EMBY_WEB_EMBED_FONT: "True"
# Log level
LOG_LEVEL: "INFO"
# Disable online fonts, use local font library only
DISABLE_ONLINE_FONTS: "True"
# Font cache configuration
FONT_CACHE_SIZE: "50"
FONT_CACHE_TTL: "60"
# Subtitle cache configuration
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 # Font directory
- ./data:/data # Database directory
- ./logs:/logs # Log directory
extra_hosts:
# Allow container to access host's Emby service
- "host.docker.internal:host-gateway"

The DISABLE_ONLINE_FONTS: "True" configuration disables online font downloads and uses local font library exclusively. If you want to automatically download fonts from the network when local fonts are missing, you can set it to "False".

3. Configure Nginx Reverse Proxy#

Create Nginx configuration file /etc/nginx/sites-available/fontinass:

This is my nginx configuration, for reference only.

/etc/nginx/sites-available/fontinass
# Upstream server configuration
upstream fontinass_backend {
server 127.0.0.1:8011;
keepalive 32;
}
upstream emby_backend {
server 127.0.0.1:8096;
keepalive 32;
}
# HTTP redirect to HTTPS
server {
listen 80;
listen [::]:80;
server_name your-domain.com;
# Redirect all HTTP requests to HTTPS
return 301 https://$host$request_uri;
}
# HTTPS main configuration
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name your-domain.com;
# SSL certificate configuration
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
# SSL optimization configuration
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;
# Security headers
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;
# Logging
access_log /var/log/nginx/fontinass.access.log;
error_log /var/log/nginx/fontinass.error.log;
# Client upload size limit
client_max_body_size 100M;
# WebSocket support (forward directly to 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;
}
# Subtitle file interception (forward to fontInAss for processing)
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 compression (for subtitle files)
gzip on;
gzip_comp_level 6;
gzip_types text/x-ssa text/plain application/x-subrip;
}
# FeiNiu/Jellyfin subtitle API (forward to 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 file modification (Web font rendering support)
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 and 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;
}
# Default forward to Emby server
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;
# Buffer configuration
proxy_buffering off;
proxy_redirect off;
}
}

Enable Nginx configuration:

Terminal window
# Create symlink to enable configuration
ln -s /etc/nginx/sites-available/fontinass /etc/nginx/sites-enabled/
# Test configuration
nginx -t
# Reload Nginx
systemctl reload nginx

4. Start fontInAss Service#

Terminal window
cd /root/docker_yaml/fontInAss
# Start container
docker compose up -d
# View logs to confirm successful startup
docker compose logs -f fontinass

Normal startup log output:

Terminal window
🤖 INFO Local font folder:/fonts
🤖 INFO Starting database and directory consistency check...
🤖 INFO Monitoring:/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

Font Library Configuration#

Adding Local Fonts#

fontInAss supports automatic monitoring of the fonts directory. After adding fonts, it will automatically scan and add them to the database.

Font download: https://pan.acgrip.com/

Note: The usability of this project depends entirely on the scale of your font library. If you only have a few fonts, it may not display properly or result in an ugly situation where some text has fonts and some doesn’t.

Terminal window
# Copy font files to font directory
cp /path/to/your/*.ttf /root/docker_yaml/fontInAss/fonts/
# Or create subdirectories for organized management
mkdir -p fonts/Chinese fonts/Japanese fonts/English
cp SourceHanSans*.ttf fonts/Chinese/

Supported font formats:

  • .ttf (TrueType Font)
  • .ttc (TrueType Collection)
  • .otf (OpenType Font)

Font Auto-Recognition Flow#

1. watchdog monitors /fonts directory in real-time
2. New font discovered → Extract metadata
- Font family name (familyName)
- Full name (fullName)
- PostScript name
- Weight
- Style (bold/italic)
3. Add to SQLite database
4. Immediately available (no container restart needed)

View font statistics:

Terminal window
# View number of font files
find /root/docker_yaml/fontInAss/fonts -type f \( -name "*.ttf" -o -name "*.ttc" -o -name "*.otf" \) | wc -l
# View font directory disk usage
du -sh /root/docker_yaml/fontInAss/fonts

Verify Deployment#

1. Check Container Status#

Terminal window
# View container running status
docker compose ps
# Should show fontinass container status as "Up"

2. Test Local API#

Terminal window
# Test fontInAss API
curl -I http://localhost:8011/subset/
# Should return HTTP/1.1 200 OK
![image-20260112164358436](https://s3.catcat.blog/images/2026/01/20260112164358682.avif)

3. Test Nginx Proxy#

Terminal window
# Test if proxy is working
curl -I https://your-domain.com/subset/
# Should return 200 OK and display fontInAss Web UI
![image-20260112162104129](https://s3.catcat.blog/images/2026/01/20260112162133271.avif)

Client Configuration#

Dual-Track Access Mode#

fontInAss uses a dual-track mode that doesn’t affect existing Emby usage habits:

Access MethodAddressPurpose
Method A (Original)http://localhost:8096Daily viewing, no subtitle processing
Method B (New)https://your-domain.comSubtitle font enhancement, automatic special font processing

Configuration Steps#

Most Emby clients support multi-server configuration:

  1. Keep original server configuration (unchanged)

  2. Add new server:

    • Open Emby client settings
    • Add new server: https://your-domain.com
    • Login with the same account
  3. Switch usage:

    • Use the new address when subtitle font enhancement is needed
    • Use the original address for daily viewing

Web UI Usage#

fontInAss provides a Web UI for batch processing subtitle files.

Access Address#

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

image-20260112162104129

Usage Flow#

1. Access Web UI
2. Upload subtitle files (drag and drop supported)
3. Wait for processing (usually a few seconds)
4. Download subtitle file with embedded fonts
5. Replace original subtitle for use
NOTE

Web UI is suitable for batch pre-processing subtitle libraries, or subtitle files used with non-Emby players. When watching through Emby daily, subtitles are processed automatically, no need to manually use Web UI.

FAQ#

Q1: Subtitles not showing font effects?#

Possible causes and solutions:

  1. Required font not in font library
    Terminal window
    # View container logs to confirm missing fonts
    docker compose logs -f fontinass | grep "missing"
    # Add missing fonts to fonts directory
    cp missing-font.ttf /root/docker_yaml/fontInAss/fonts/

Q2: How to switch back to online font mode?#

If you find your local font library is incomplete, you can enable online font downloads as a supplement:

I checked the code, it seems the deployment stores a copy of XZ’s font package on 123 cloud storage.

image-20260112162515483

docker-compose.yml
environment:
DISABLE_ONLINE_FONTS: "True" # Disable online fonts
DISABLE_ONLINE_FONTS: "False" # Enable online fonts

Restart container after modification:

Terminal window
docker compose down
docker compose up -d

Online fonts will be automatically downloaded to the fonts/download/ directory.

Q3: How to view subtitle processing logs?#

fontInAss provides detailed logging:

Terminal window
# View container logs in real-time
docker compose logs -f fontinass
# View missing font records
cat /root/docker_yaml/fontInAss/logs/miss_logs.txt
# View Nginx access logs
tail -f /var/log/nginx/fontinass.access.log

image-20260112194939138

Performance Optimization#

Font Cache Configuration#

fontInAss uses a three-level cache strategy: Memory cache → Local database → Online database.

docker-compose.yml
environment:
FONT_CACHE_SIZE: "50" # Font cache count (adjust based on memory)
FONT_CACHE_TTL: "60" # Font cache expiration time (minutes)
SUB_CACHE_SIZE: "50" # Subtitle cache count
SUB_CACHE_TTL: "60" # Subtitle cache expiration time (minutes)

Recommended configuration:

  • Sufficient memory (8GB+): FONT_CACHE_SIZE: "100"
  • Limited memory (2-4GB): FONT_CACHE_SIZE: "30"

Nginx Optimization#

If you have a large user base, you can enable Nginx caching:

# Add to http block
proxy_cache_path /var/cache/nginx/fontinass levels=1:2 keys_zone=fontinass_cache:10m max_size=1g inactive=60m;
# Add to location ~ /videos/.*/Subtitles/ block
proxy_cache fontinass_cache;
proxy_cache_valid 200 60m;
proxy_cache_key "$scheme$request_method$host$request_uri";

Maintenance Operations#

Daily Maintenance#

Terminal window
# View running status
docker compose ps
# View logs
docker compose logs --tail=100 fontinass
# Restart service
docker compose restart fontinass
# Update image
docker compose pull
docker compose up -d

Backup Important Data#

Terminal window
# Backup font database and configuration
tar -czf fontinass-backup-$(date +%Y%m%d).tar.gz \
docker-compose.yml \
data/ \
fonts/

Clear Cache#

Terminal window
# Clear Docker cache
docker system prune -a
# Clear Nginx cache (if enabled)
rm -rf /var/cache/nginx/fontinass/*

Summary#

fontInAss perfectly solves the Emby/Jellyfin special font subtitle display issue through intelligent font subsetting and embedding technology. The dual-track deployment mode introduced in this article maintains the stability of the original service while providing subtitle font enhancement functionality - a solution suitable for anyone who wants a hassle-free setup.

Use Cases#

  • Watching anime subtitles with special fonts
  • Correctly displaying subtitle effects on mobile devices
  • Subtitle groups producing and distributing subtitles with embedded fonts
  • Home media center subtitle optimization

Hope this article helps you successfully deploy the fontInAss service and enjoy a perfect subtitle viewing experience!

Deploy fontInAss Subtitle Font Processing Service with Docker Compose
https://catcat.blog/en/2026/01/deploy-fontinass-emby-subtitle-font
作者
猫猫博客
发布于
2026-01-12
许可协议
CC BY-NC-SA 4.0