Jellyfin

于 2023-09-21 发布 , 于 2023-09-21 更新

之前一直遇到困难,怎么在不同的设备上播录播能够同步。vlc是做不到的,只能做到播+弹幕。在纠结怎么把hexo转移到wordpress的时候,误打误撞打开了一个bro的博客,目前在用的一些Docker,发现了Jellyfin这个项目。

Jellyfin有很多版本,甚至有中国特供版(国内玩家自己魔改的)。我安装的是官方的镜像。

Docker

初步启动

对于这种应用,有docker肯定是跑docker了。首先要创建一些目录给它存数据。

根据文档的Docker Compose可知,我们需要手动创建两个目录:configcache。另外,存放用来远程观看的媒体文件的目录也要挂载进去,这里假设是/mnt/media。由于docker本身就提供了环境隔离,所以我就不指定用户了,直接用root就行。那么首先,mkdir上面的两个目录,得到以下目录结构:

~/docker/jellyfin/
|-- config/
|-- cache/
`-- docker-compose.yaml

docker-compose.yaml的内容是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
version: '3.5'
services:
  jellyfin:
    image: jellyfin/jellyfin
    container_name: jellyfin
    network_mode: 'host'
    volumes:
      - ./config:/config
      - ./cache:/cache
      - "/mnt/media:/media:ro"
      - "/mnt/media/font:/font:ro"
    restart: 'always'
    # Optional - alternative address used for autodiscovery
    environment:
      - JELLYFIN_PublishedServerUrl=http://example.com
    # Optional - may be necessary for docker healthcheck to pass if running in host network mode
    extra_hosts:
      - "host.docker.internal:host-gateway"

可以看到,为什么比官方文件多挂载了个font目录呢?其实font目录里面放的是微软雅黑的ttf字体文件,由于很多弹幕录制器默认的字体都是微软雅黑,如果不提供这个备用字体,jellyfin渲染的弹幕就会变成方框。具体的看#弹幕是方框怎么办

如果要把jellyfin放到公网上,就要设置一下JELLYFIN_PublishedServerUrl环境变量,改成自己的域名。

一切准备就绪之后,就可以docker compose up -d启动容器了。Jellyfin默认的访问端口是8096,这一点官方文档没有写。访问http://<IP>:8096来打开网页界面,进行安装配置。这里有个小坑,配置了一步之后要记得按下一步,直到配置完成显示登录界面为止——我当时傻逼了,设置完挂载目录之后没有按下一步,搞到不停循环初始化配置。

nginx反向代理

官方文档有所描述,Networking/Nginx,非常详尽。这里只讲对于本地Nginx+FRP+公网Nginx的环境下,如何利用类似split DNS的功能以便在家里可以直接连接Home Server观看而不会舍近求远让公网转发。

这里省略两个Nginx互相认证的client auth部分;本地Nginx监听443和80,frp(或rathole)将本地443映射到VPS的8043;示例域名用stream.example.comstream.lan本地的DNS配置了响应stream.example.comstream.lan为运行Jellyfin的本机的IP(10.0.0.1)。

本地Nginx

本地Nginx需要兼顾HTTP和HTTPS的请求,不过反向代理的部分都是一样的,所以可以单独保存为/etc/nginx/snippets/jellyfin.conf。注意第一第二行的指令是设置用127.0.0.1的DNS服务器查询jellyfin这个host的IP地址,以便后面的转发使用。这种设置是为了适应jellyfin部署在另一个IP地址的服务器上、Nginx是作为负载均衡器的架构而存在的,这里有两种选择:1. 如果你的DNS服务器可以配置,那就设置响应jellyfin这个域名为运行Jellyfin的服务器的IP地址,如果是本文这种同一台机运行的就响应为127.0.0.1;2. 直接set $jellyfin 127.0.0.1。其他基本都是直接从官方文档里抄过来的,也是很常见的反向代理指令。

nginx
set $jellyfin jellyfin;
resolver 127.0.0.1 valid=30;

add_header X-XSS-Protection "0"; # Do NOT enable. This is obsolete/dangerous
add_header X-Content-Type-Options "nosniff";
add_header Origin-Agent-Cluster "?1" always;

client_max_body_size 40M;

location = / {
    return 302 http://$host/web/;
    #return 302 https://$host/web/;
}

location / {
    # Proxy main Jellyfin traffic
    proxy_pass http://$jellyfin:8096;
    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-Protocol $scheme;
    proxy_set_header X-Forwarded-Host $http_host;

    # Disable buffering when the nginx proxy gets very resource heavy upon streaming
    proxy_buffering off;
}

location = /web/ {
    # Proxy main Jellyfin traffic
    proxy_pass http://$jellyfin:8096/web/index.html;
    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-Protocol $scheme;
    proxy_set_header X-Forwarded-Host $http_host;
}

location /socket {
    # Proxy Jellyfin Websockets traffic
    proxy_pass http://$jellyfin:8096;
    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_set_header X-Forwarded-Protocol $scheme;
    proxy_set_header X-Forwarded-Host $http_host;
}

然后就是server部分,80端口的设置两个域名,一个是内网域名,一个是split DNS解析的外网域名:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
server {
    listen 10.0.0.1:80;
    listen 127.0.0.1:80;
    server_name stream.example.com stream.lan;
    include /etc/nginx/snippets/jellyfin.conf;
}

server {
    listen 443 ssl http2;
    server_name stream.example.com;

    # SSL双向认证部分

    include /etc/nginx/snippets/jellyfin.conf;
}

如果你不打算公网访问,把443那个server去掉,然后重启nginx应该就能用stream.lan来访问Jellyfin了。

公网Nginx

公网的Nginx其他部分都是通用的HTTPS服务器的东西,只有location /需要这样写:

1
2
3
4
5
6
7
8
9
10
11
12
location / {
    proxy_ssl_server_name on;
    proxy_ssl_name $host;
    proxy_pass https://127.0.0.1:8043/;
    proxy_set_header X-Real-IP $proxy_protocol_addr;
    proxy_set_header X-Forwarded-For $proxy_protocol_addr;
    proxy_set_header Host $http_host;
    proxy_set_header cookie $http_cookie;
    proxy_set_header Proxy-Connection "";
    # SSL双向认证部分
    proxy_http_version 1.1;
}

注意,由于我的Nginx是开了proxy_protocol的,所以X-Real-IPX-Forwarded-For的参数是$proxy_protocol_addr,如果你的nginx没有开proxy_protocol,请改成以下这样:

proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

DNS设置

以Mosdns为例,基于easymosdns的配置,在hosts.txt添加以下内容就行:

1
2
3
jellyfin 127.0.0.1
stream.example.com 10.0.0.1
stream.lan 10.0.0.1

杂项

访问过https之后没办法访问http怎么办

在家里之外的网络访问stream.example.com会自动转发到https://stream.example.com,而在家里访问stream.example.com就会访问http://stream.example.com。但是这里就出现了一个问题,如果在外面访问过https版本的,浏览器就会默认自动给你的网址改成https,因为浏览器自动cache了。解决这个问题的办法是让nginx告诉浏览器别cache,把以下内容添加到/etc/nginx/snippets/jellyfin.conf里:

1
2
3
add_header Cache-Control 'no-store' always;
add_header Cache-Control 'no-cache' always;
expires 0;

弹幕是方框怎么办

弹幕多数都是把字体设置为微软雅黑,但是jellyfin默认字体里没有微软雅黑,所以渲染的时候就会变成框框。解决办法,首先是像上面一样把一个用来放字体的文件夹挂载进容器(容器内目录是什么没有所谓,记得名字就可以,网页控制台会有目录浏览器来选的)。然后是把微软雅黑的ttf放进这个文件夹里。最后在Jellyfin的控制台选择备用字体目录,打开备用字体选项。

image-20230921225354216

记得按保存。

Jellyfin支持的总字体大小,指的是整个外挂font目录里所有的字体的总大小,不能超过20M。这个意思是,如果你font目录里放了超过20M的字体,是所有字体都不会被加载,而不是超过20M的字体不会加载。

目录