2093 字
10 分钟
Emby 开心版安装、使用
2025-03-25
2025-03-27

安装#

使用 docker-compose 安装,docker-compose.yml 文件如下:

version: '3.8'
services:
embyserver-happy:
image: amilys/embyserver
platform: linux/amd64 # 强制使用 amd64 架构(我这里使用的是 arm64 版本,如果使用 amd64 版本,请删除此行)
container_name: emby-happy
privileged: true
volumes:
- ./emby/config:/config # 配置文件
- ./emby/webdav:/docker/webdav # 挂载 webdav 目录
- ./emby/local:/docker/local # 本机影音文件目录
ports:
- 8096:8096
restart: unless-stopped

在浏览器中访问 http://localhost:8096 即可访问 Emby。

挂载目录#

挂载目录为 ./emby/local,目录结构如下:

./emby/local 目录下存放你的影音文件,然后在浏览器访问 emby 服务,进入 设置 -> 服务器 -> 媒体库 -> 添加媒体库 -> 选择 从文件夹添加,然后选择 /docker/local 目录,然后扫描,等待扫描完成后,你就可以在首页中看到你的影音文件了。

第三方播放#

使用 InfuseForwardVidHubSenplay 等第三方播放器,可以播放 emby 中的影音文件。

alt text

局限#

随着影视资源库的不断扩充,对于本地存储的容量要求也越来越高,此时有两条路可以选择

  1. 使用 NAS 存储
  2. 使用云盘挂载

对于 NAS 存储,这需要一笔不小的开支,而且需要考虑电费、散热、噪音等问题。

而我之前使用的是阿里云盘,且开通了它的三年会员,所以就自然而然选择了云盘挂载。

云盘挂载#

总体思路是将云盘转换成 webdav 服务,然后在将 webdav 挂载为本地目录。

1.云盘转 webdav#

使用 alist 很方便的将云盘转换成 webdav 服务,只需要在 alist 中添加阿里云盘即可。

TIP

如果你没有阿里云盘的第三方权益会员,可以参考 alist 挂载阿里云盘 实现获取 阿里云盘 TV token 解除限速。

2.1 使用 Rclone 挂载为本地目录#

可以使用 Rclone 挂载 webdav 为本地目录,然后使用 emby 添加此目录。

  1. 安装 Rclone

macos 不能使用brew 安装,需要使用源码安装。

Terminal window
curl https://rclone.org/install.sh | sudo bash
  1. 配置 Rclone
Terminal window
rclone config

根据提示创建 remote -> 输入名称 -> 选择 webdav -> 输入 url -> 选择 Other site/service or software -> 输入用户名 -> 选择 Yes, type in my own password -> 输入两次密码 -> 回车完成配置

TIP

url 为 alist 的 webdav 地址,例如:https://example.com/dav/,用户名密码为你的 alist 用户名密码。

  1. 挂载 webdav
Terminal window
# 直接后台挂载
rclone mount mywebdav:/ ~/docker/emby/webdav --network-mode --cache-dir cache --vfs-cache-mode full --header "Referer:" --daemon
# 使用 tmux 挂载
tmux new-session -d -s mount-rclone rclone mount mywebdav:/ ~/docker/emby/webdav --network-mode --cache-dir cache --vfs-cache-mode full --header "Referer:" --daemon
# 关闭挂载
#macos 使用
umount ~/docker/emby/webdav
#windows、linux 使用
fusermount -u ~/docker/emby/webdav
TIP

rclone mount: 挂载命令

mywebdav:: 刚刚配置的 remote 名称

~/docker/emby/webdav: 你的挂载目录

--network-mode: 启用网络模式,该模式会让 rclone mount 使用网络流量来访问和同步文件,而不是使用本地缓存。这可以有效减少磁盘占用,但会使文件访问速度依赖于网络连接。

--cache-dir cache: 设置本地缓存目录。在此命令中,cache 是一个相对路径或绝对路径,指定 rclone 存储本地缓存的地方。缓存的文件可以加速后续访问操作,尤其是针对大量小文件或频繁访问的情况。

--vfs-cache-mode full: FS(虚拟文件系统)缓存模式。在 rclone mount 中,full 模式表示 rclone 将缓存文件的全部内容。这对于大型文件(例如视频文件)的操作尤其重要,因为它将所有文件数据保存在本地缓存中,从而提高性能。该模式确保每个文件都完全缓存并能够进行读取和修改。

--header "Referer:" : 必须加上,否则无法播放

--daemon: 后台运行

WARNING

由于缓存的原因,可能导致挂载后再网盘处编辑文件,挂载的目录不会同步更新,此时需要手动关闭挂载,重新挂载。

2.2 使用 strm 文件模拟本地目录#

思路来自于:

xtxt19931207
/
emby-alist
Waiting for api.github.com...
00K
0K
0K
Waiting...

大体思路就是在 emby 的挂载目录中存放和 alist 1:1 一样的目录结构,但是文件内容由 mp4 -> strm 文件。

且 strm 文件内容为 webdav 的 url 地址,emby 会自动识别 strm 文件,并进行播放。

我在使用 emby-alist 仓库的代码时发现它存在一个 bug 无法识别所有的文件目录,因此我对它进行了修改,并添加了下载字幕的功能。

IMPORTANT
# 替换 webdav_url、save_mulu、username、password 为你自己的参数
webdav_url = 'https://example.com/dav/folder/' # alist webdav 地址 folder 为你的文件夹名称
save_mulu = './' # 输出路径
username = '' # 用户名 alist 用户名
password = '' # 密码 alist 密码
download_subtitle = False # 是否下载字幕文件
from webdav3.client import Client
import os, time, requests
def list_files(webdav_url, username, password):
# 创建WebDAV客户端
options = {
'webdav_hostname': webdav_url,
'webdav_login': username,
'webdav_password': password
}
client = Client(options)
mulu = []
wenjian = []
q = 1
while q < 15:
try:
# 获取WebDAV服务器上的文件列表
files = client.list()
except:
q += 1
print('连接失败,1秒后重试...')
time.sleep(1)
else:
if q > 1:
print('重连成功...')
break
if q >= 15:
print(f"连接 {webdav_url} 失败,已达到最大重试次数")
return [], []
for file in files[1:]:
if file[-1] == '/':
mulu.append(file)
else:
wenjian.append(file)
return mulu, wenjian
def traverse_webdav(base_url, username, password, max_depth=10, current_depth=0):
"""
递归遍历WebDAV目录,获取所有目录和文件
Args:
base_url: WebDAV基础URL
username: 用户名
password: 密码
max_depth: 最大递归深度,防止无限递归
current_depth: 当前递归深度
Returns:
tuple: (所有目录列表, 所有文件URL列表)
"""
if current_depth >= max_depth:
print(f"警告: 达到最大递归深度 {max_depth},停止在 {base_url} 的递归")
return [], []
print(f"扫描目录: {base_url}")
# 获取当前目录下的文件和子目录
directories, files = list_files(base_url, username, password)
all_directories = [base_url]
all_files = [base_url + f for f in files]
# 递归处理子目录
for directory in directories:
dir_url = base_url + directory
sub_dirs, sub_files = traverse_webdav(dir_url, username, password, max_depth, current_depth + 1)
all_directories.extend(sub_dirs)
all_files.extend(sub_files)
return all_directories, all_files
def process_media_file(file_url, save_path, webdav_url):
"""处理媒体文件,创建.strm文件"""
if not os.path.exists(save_path + file_url.replace(webdav_url, '')[:-3] + 'strm'):
print('正在处理:' + file_url.replace(webdav_url, ''))
try:
os.makedirs(os.path.dirname(save_path + file_url.replace(webdav_url, '')[:-3] + 'strm'), exist_ok=True)
with open(save_path + file_url.replace(webdav_url, '')[:-3] + 'strm', "w", encoding='utf-8') as f:
f.write(file_url.replace('/dav', '/d'))
except:
try:
# 处理包含冒号等特殊字符的文件名
os.makedirs(os.path.dirname(save_path + file_url.replace(webdav_url, '').replace(':', '.')[:-3] + 'strm'), exist_ok=True)
with open(save_path + file_url.replace(webdav_url, '').replace(':', '.')[:-3] + 'strm', "w", encoding='utf-8') as f:
f.write(file_url.replace('/dav', '/d'))
except Exception as e:
print(f"处理失败: {file_url.replace(webdav_url, '')} - 错误: {str(e)}")
print(f"{file_url.replace(webdav_url, '')}处理失败,文件名包含特殊符号,建议重命名!")
def download_subtitle_file(file_url, save_path, webdav_url):
"""下载字幕文件"""
if not os.path.exists(save_path + file_url.replace(webdav_url, '')):
p = 1
while p < 10:
try:
print('正在下载:' + save_path + file_url.replace(webdav_url, ''))
r = requests.get(file_url.replace('/dav', '/d'))
os.makedirs(os.path.dirname(save_path + file_url.replace(webdav_url, '')), exist_ok=True)
with open(save_path + file_url.replace(webdav_url, ''), 'wb') as f:
f.write(r.content)
except Exception as e:
p += 1
print(f'下载失败,1秒后重试... 错误: {str(e)}')
time.sleep(1)
else:
if p > 1:
print('重新下载成功!')
break
if p >= 10:
print(f"下载失败: {file_url.replace(webdav_url, '')} - 已达到最大重试次数")
# 主程序
if __name__ == "__main__":
# 输入WebDAV地址、用户名和密码
webdav_url = 'https://example.com/dav/folder/' # alist webdav 地址 folder 为你的文件夹名称
save_mulu = './' # 输出路径
username = '' # 用户名 alist 用户名
password = '' # 密码 alist 密码
# 控制是否下载字幕文件
download_subtitle = False # 设置为 False 将不会下载字幕文件
# 设置最大递归深度
max_depth = 10 # 可以根据实际需求调整
print(f"开始遍历 WebDAV 目录: {webdav_url}")
print(f"字幕下载功能: {'已启用' if download_subtitle else '已禁用'}")
start_time = time.time()
# 递归遍历所有目录和文件
all_directories, all_files = traverse_webdav(webdav_url, username, password, max_depth)
print(f"遍历完成,共发现 {len(all_directories)} 个目录,{len(all_files)} 个文件")
print(f"遍历耗时: {time.time() - start_time:.2f} 秒")
# 处理所有文件
processed_count = 0
media_count = 0
subtitle_count = 0
for file_url in all_files:
extension = file_url.split('.')[-1].upper() if '.' in file_url else ''
if extension in ['MP4', 'MKV', 'FLV', 'AVI']:
process_media_file(file_url, save_mulu, webdav_url)
processed_count += 1
media_count += 1
elif extension in ['ASS', 'SRT', 'SSA'] and download_subtitle:
# 只有当 download_subtitle 为 True 时才下载字幕文件
download_subtitle_file(file_url, save_mulu, webdav_url)
processed_count += 1
subtitle_count += 1
print(f'处理完毕!共处理 {processed_count} 个文件(媒体文件: {media_count}, 字幕文件: {subtitle_count})')
print(f'字幕下载功能: {"已启用" if download_subtitle else "已禁用"}')
input('按任意键退出...')
TIP

经测试无法通过 emby 播放 strm 文件,但是通过第三方播放器则可以正常播放。

emby 添加资源库#

在 emby 中添加资源库,选择 从文件夹添加,然后选择 /docker/emby 目录,然后扫描,等待扫描完成后,你就可以在首页中看到你的影音文件了。

alt text

alt text

Emby 开心版安装、使用
https://www.mihouo.com/posts/docker/emby-cracked-version-installation-and-usage/
作者
发布于
2025-03-25
许可协议
CC BY-NC-SA 4.0