OneKuma

OneKuma's Blog

One Lonely Kuma.
github
bilibili
twitter

在伺服器用 WebDAV 部署 Jellyfin

接著上文 折騰了一下阿里雲盤 + AList + Rclone + AnimePaste 繼續倒騰。

在伺服器上,將 阿里雲盤 掛載到 AList 上,再用 rclone 掛載到本地磁碟,最後用 Jellyfin 暴露出動畫媒體庫。

af0c5f3688237ea4b153b64ea1a251f5

Jellyfin#

首先,安裝 Jellyfin

dnf install -y https://mirrors.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm https://mirrors.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-$(rpm -E %fedora).noarch.rpm

dnf install -y https://repo.jellyfin.org/releases/server/fedora/stable/server/jellyfin-10.8.10-1.fc36.x86_64.rpm

dnf install -y https://repo.jellyfin.org/releases/server/fedora/stable/web/jellyfin-web-10.8.10-1.fc36.noarch.rpm

# 啟動 Jellyfin
systemctl start jellyfin

# 開機自動啟動 Jellyfin
systemctl enable jellyfin

啟動後,可以通過 http://伺服器IP:8096 訪問到 Jellyfin 媒體庫了(伺服器防火牆打開 8096 端口)。

AList#

直接用 Docker 部署 AList

#!/usr/bin/bash

docker stop alist 2> /dev/null

docker rm alist 2> /dev/null

docker run -d --name=alist --restart=always \
  -v /etc/alist:/opt/alist/data -p 5244:5244 \
  -e PUID=0 -e PGID=0 -e UMASK=022 xhofe/alist:latest

啟動後,查看容器日誌獲得登錄密碼。

docker logs alist

啟動後,可以通過 http://伺服器IP:5244 訪問到 AList 了(伺服器防火牆打開 5244 端口)。然後,在它的 WebUI 上配置阿里雲盤掛載到 /aliyundriver

約定動畫目錄是阿里雲盤的 /anime/,即 AList 的 /aliyundriver/anime/

qbittorrent#

version: '3.9'

services:
  alist:
    image: xhofe/alist:latest
    container_name: alist
    restart: always
    environment:
      - PUID=0
      - PGID=0
      - UMASK=022
      - TZ=Asia/Shanghai
    volumes:
      - /etc/alist:/opt/alist/data
    networks:
      - alist_net
    ports:
      - 5244:5244

  qbittorrent:
    image: lscr.io/linuxserver/qbittorrent:latest
    container_name: qbittorrent
    restart: unless-stopped
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Asia/Shanghai
      - WEBUI_PORT=8080
    volumes:
      - ./appdata/config:/config
      - ./downloads:/downloads
    networks:
      - alist_net
    ports:
      - 8080:8080
      - 6881:6881
      - 6881:6881/udp

networks:
  alist_net:

Rclone#

[alist]
type = webdav
url = http://127.0.0.1:5244/dav/
user = admin
pass = xxxyyyzzz

密碼已隱藏。

寫了個腳本 mount-anime.sh 方便掛載本地目錄。

#!/usr/bin/bash

mount_dir="/jellyfin/anime"
cache_dir="/root/.rclone/cache/anime" 
log_path="/var/log/rclone-anime.log"

function bootstrap() {
  mkdir -p $mount_dir
  rm $log_path
  
  rclone mount alist:/aliyundriver/anime/ $mount_dir \
    --header "Referer:https://www.aliyundrive.com/" \
    --vfs-cache-mode writes --vfs-read-chunk-size-limit 1G --vfs-read-chunk-size 256M \
    --cache-dir $cache_dir --dir-cache-time 5m --vfs-cache-max-size 10G \
    --buffer-size 128M \
    --no-check-certificate --allow-non-empty --allow-other \
    --uid $(id -u jellyfin) --gid $(id -g jellyfin) --umask 022 \
    --log-file $log_path $@
}

function stop() {
  fusermount -u $mount_dir 2> /dev/null
  ps -ef | grep rclone | grep -v grep | awk '{print $2}' | xargs kill 2> /dev/null
}

case "$1" in
  "")
    stop
    bootstrap --daemon
  ;;
  "service")
    stop
    bootstrap
  ;;
  "space")
    echo $mount_dir
  ;;
  "logs")
    tail -f $log_path
  ;;
  "stop")
    stop
  ;;
esac

注意:掛載的本地目錄($mount_dir)必須給 jellyfin 使用者權限,否則 Jellyfin 將無法識別。

使用方法:

# 作為 daemon 進行 mount
$ ./mount-anime.sh

# 查看日誌
$ ./mount-anime.sh logs

# 停止
$ ./mount-anime.sh stop

順便再搞到 systemd 裡,重啟的時候自動 mount。

[Unit]
Description=Mount Anime Directory
Documentation=man:rclone(1)
After=network.target
After=docker.service
Before=jellyfin.service

[Service]
Type=simple
ExecStart=/path/to/mount-anime.sh service
ExecStop=/path/to/mount-anime.sh stop

[Install]
WantedBy=default.target

修改 mount-anime.sh 腳本的路徑。

# 將上面的 service 文件移動到 systemd 目錄下
$ cp /path/to/mount-anime.service /etc/systemd/system/

# 重啟,並啟動服務
$ systemctl daemon-reload

$ systemctl enable mount-anime.service

$ systemctl start mount-anime.service

nginx(可選)#

順便也把它暴露到一個域名上,方便記憶。

把下面這段配置修改後丟到 /etc/nginx/conf.d/jellyfin.conf。你需要修改:

  • server_name:你的域名;
  • ssl_certificate / ssl_certificate_key:你的 SSL 證書。
server {
    listen       80;
    listen       [::]:80;
    server_name  <SERVER_NAME>;

    # Uncomment to redirect HTTP to HTTPS
    return 301 https://$host$request_uri;
}

server {
    listen       443 ssl http2;
    listen       [::]:443 ssl http2;
    server_name  <SERVER_NAME>;

    ## The default `client_max_body_size` is 1M, this might not be enough for some posters, etc.
    client_max_body_size 20M;

    # use a variable to store the upstream proxy
    # in this example we are using a hostname which is resolved via DNS
    # (if you aren't using DNS remove the resolver line and change the variable to point to an IP address e.g `set $jellyfin 127.0.0.1`)
    # set $jellyfin jellyfin;
    # resolver 127.0.0.1 valid=30;
    set $jellyfin 127.0.0.1;

    ssl_certificate     <SSL_PEM>;
    ssl_certificate_key <SSL_KEY>;
    #include /etc/letsencrypt/options-ssl-nginx.conf;
    #ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
    add_header Strict-Transport-Security "max-age=31536000" always;
    #ssl_trusted_certificate /etc/letsencrypt/live/DOMAIN_NAME/chain.pem;
    ssl_stapling on;
    ssl_stapling_verify on;

    # Security / XSS Mitigation Headers
    # NOTE: X-Frame-Options may cause issues with the webOS app
    # add_header X-Frame-Options "SAMEORIGIN";
    add_header X-XSS-Protection "1; mode=block";
    add_header X-Content-Type-Options "nosniff";

    # Content Security Policy
    # See: https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP
    # Enforces https content and restricts JS/CSS to origin
    # External Javascript (such as cast_sender.js for Chromecast) must be whitelisted.
    # NOTE: The default CSP headers may cause issues with the webOS app
    #add_header Content-Security-Policy "default-src https: data: blob: http://image.tmdb.org; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' https://www.gstatic.com/cv/js/sender/v1/cast_sender.js https://www.gstatic.com/eureka/clank/95/cast_sender.js https://www.gstatic.com/eureka/clank/96/cast_sender.js https://www.gstatic.com/eureka/clank/97/cast_sender.js https://www.youtube.com blob:; worker-src 'self' blob:; connect-src 'self'; object-src 'none'; frame-ancestors 'self'";

    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 block for /web - This is purely for aesthetics so /web/#!/ works instead of having to go to /web/index.html/#!/
    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;
    }
}

最後#

在 Jellyfin 上初始化你的媒體庫,添加動畫相關的插件和 jellyfin-plugin-bangumi 插件,並指定媒體庫從這些插件中下載元數據。

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。