---------------------------------------------
---下面会有一段介绍和实现时遇到的问题,直接配置可以直接划到“配置”标题~---
简单介绍一下,通过 Python 搭配 Nginx 实现的云盘302直链功能,需要 Alist 提供文件链接,扫库使用的是本地 Rclone 挂载,同时使用 Overlayfs 加速目录和图片的加载(如果有人感兴趣也可以以后讲讲),支持 本地媒体文件 和 云盘文件 的混搭,实现仅云盘挂载(๐•ᴗ•๐)径进行302跳转直链。由于暂时对strm没有需求,所以目前并不支持strm的直链。
灵感来自于 MisakaFxxk/Go_stream 和 bpking1/embyExternalUrl,前者提供了通过 Nginx 反代 Python 服务器的想法,后者则不用说了,开创了云盘302的先河,十分感谢两位作者的开源,能让我也贡献出自己的一点新想法。
该项目的主要特色其实并不是302跳转,而是本地缓存功能。该缓存效果在面对存储访问延迟较高的情况下效果较好,并不仅限于云盘,比如我在A国的Nas上存储了一些文件,但距离Emby服务器距离较远,延迟也很高,也可以通过该功能实现加速。
当前缓存逻辑为在第一次播放云盘文件时缓存该视频的前15秒到本地磁盘,并在后续请求播放的时候优先返回本地磁盘中的内容,从而解决开始播放时的加载时间过长的问题。
通过测试 Fileball 的 mpv 播放器,后端存储为 Onedrive时,媒体文件的开始加载时间从原本的十秒以上,可以做到现在的几乎秒开。
同时由于实现的逻辑略抽象,所以并不是所有播放器都可以达到此效果。缓存实现的主要逻辑为播放器支持分段请求播放,并且可以在服务端仅响应视频文件的部分内容后,主动发起第二次请求文件的剩余内容。而关于第二条,知名的开源播放器 VLC 以及 Infuse 却都并不支持这样的操作,默认在播放完第一次响应的缓存内容后认定视频已经结束,纵使在请求头指出了该响应的文件大小,以及整个文件的完整大小。
可能是该需求实在过于小众,在网上搜寻许久只搜到一条VLC相关问题的帖子,但也在几行回复之后没有了下文。在咨询群友后得知,也曾之前咨询过 Infuse 开发团队,指出目前并不打算支持该功能(虽然我和他认为该功能应该是算最基本的网络请求)。并且HTTP1.1协议中并没有明确指出当请求整个资源时,服务器仅响应部分内容后客户端是否应该继续发起后续请求,也没有说服务器就不应该响应部分内容,所以该问题只能暂时搁置,VLC和Infuse客户端也无缘这次的缓存加速了。
PS:上述描述中的云盘均为Onedrive,由于我没有试过115和阿里云盘,可能不存在开始播放时加载速度慢的问题,可以仅当此项目为302直链跳转使用
PSS:听说cloudflare workers即将支持python,或许以后可以使用cloudflare workers+R2实现将文件也缓存到云端的做法)
PSSS:改了半天,但还是要审核,不知道触碰到什么关键词了
配置
更加详细的介绍和配置说明可以参考仓库的Readme,仓库链接为:https://gith(๐•ᴗ•๐).com/zsbai/EmbyToAlist
示例配置文件为根目录下的config.example.py
,示例配置文件中也有相关的介绍
配置 | 说明 |
embyServer | Emby服务器地址 |
emby_key | Emby Api密钥(非必需) |
alistServer | Alist服务器地址 |
alist_key | Alist Api密钥(必需) |
AlistP(๐•ᴗ•๐)licStorageURL | 反代后端存储的主机名,也可以直接在 Alist 中配置,二选一 |
embyP(๐•ᴗ•๐)licURL | 本地媒体文件所使用的地址,没有特殊需要请填写Emby公网域名 |
notRedirectPaths | 列表,本地媒体文件存储的(๐•ᴗ•๐)径,当媒体文件在该配置中的(๐•ᴗ•๐)径下,则不会使用云盘直链 |
convertSpecialChars | 布尔值,设计之初为解决Rclone搭配Onedrive出现的字符问题,现不再建议使用 |
specialCharsList | 列表,设计之初为Rclone搭配Onedrive导致出现问题的字符,现不再建议使用 |
convertMountPath | 布尔值,为应对Alist(๐•ᴗ•๐)径和Rclone挂载(๐•ᴗ•๐)径不一致的问题<br />举个例子,假设Rclone挂载(๐•ᴗ•๐)径为/mnt/movie/xxx ,Alist配置(๐•ᴗ•๐)径为/movie/xxx ,则填写mountPathPrefix 为/mnt |
mountPathPrefix | 需要移除的(๐•ᴗ•๐)径前缀 |
enableCache | 是否启用本地缓存 |
cachePath | 缓存存放(๐•ᴗ•๐)径 |
cacheClientBlacklist | 不完全支持的客户端UA |
部署 & 使用
该项目实际只由main.py
一个文件组成,通过config.py
配置选项,如果不想使用WSGI服务器,可直接通过python3 main.py
启动。程序默认监听60001
端口,同时使用 Flask 自带的 web 服务可能会导致一些性能问题。
启动服务器后,需要配置Nginx,将播放(๐•ᴗ•๐)径反代到本地60001
端口。如果有使用 本地文件+云盘文件 的需求,则需要设置一个新的反向代理(๐•ᴗ•๐)径以防止程序陷入无限自我重定向的循环,以下是相关的Nginx配置文件示例:
location ~* ^/preventRedirect/emby/videos/(\d*)/(stream|original).* {
rewrite ^/preventRedirect/(.*)$ /$1 break;
proxy_pass http://127.0.0.1:8000;
#proxy_ignore_headers X-Accel-Expires Expires Cache-Control;
#proxy_set_header Range $slice_range;
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 Upgrade $http_upgrade;
proxy_set_header Connection "";
add_header Strict-Transport-Security "max-age=31536000";
proxy_http_version 1.1;
add_header Cache-Control no-cache;
proxy_cache off;
}
# /emby/Videos/12345/xxx/S(๐•ᴗ•๐)ti(๐•ᴗ•๐)es/3/0/Stream.ass?api_key=xx
location ~* /videos/(\d*)/(stream|original).* {
proxy_cache off;
proxy_buffering off;
proxy_set_header Host $host;
proxy_set_header Range $http_range;
proxy_set_header If-Range $http_if_range;
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_pass http://127.0.0.1:60001;
}
if(window.hljsLoader && !document.currentScr(๐•ᴗ•๐).parentNode.hasAttribute('data-s9e-livepreview-onupdate')) {
window.hljsLoader.highlightBlocks(document.currentScr(๐•ᴗ•๐).parentNode);
}
注意:为确保请求头中的Range
不丢失,确保中间的任何反代服务关闭缓存,如Cloudflare等。启用缓存会导致Range
请求头丢失,从而使本地的缓存功能失效。
更加详细的缓存逻辑解释
如果在配置文件中启用缓存,会在第一次播放云盘视频的时候缓存该视频文件的前15秒钟(通过码率计算得出),并在下次播放的时候先行返回本地的缓存文件,用于减少刚开始播放时的缓冲时间。该功能的加速效果可能因不同的播放器的播放逻辑而产生少许变化。
假设一个电影的码率为 30Mbps,前 15s 的大小大约为 50MB;而对于普通的一集番剧,前 15s 的大小大约只有几M。此功能可根据本地存储(๐•ᴗ•๐)的大小自行决定是否开启。
已知问题:并不是所有播放器支持该缓存逻辑,在面对不支持的播放器时,需要将播放器关键词UA填入配置文件中。如果播放器不支持缓存的情况下启用缓存,会出现播放器播放完缓存的内容后认为视频已经结束,直接退出并标记该视频“已播放完成”。
截至目前,发现 “VLC 播放器 (如 Fileball 免费版)“ 和 ” Infuse 播放器” 不支持该缓存逻辑。