
### 文章更新记录

#### 2025-02-24

1.fix(emby2Alist&plex2Alist): 修复直链缓存

#### 2024-12-28

1.fix(emby2Alist&plex2Alist): 修复 getClientSelfAlistLink 编码

2.fix(emby2Alist&plex2Alist): 修改内网IP的识别通过header中的X-Real-IP、Proxy-Client-IP等实现

3.fix(emby2Alist&plex2Alist): 修复错误的 routeRule 分组规则

#### 2024-12-08

1.fix(emby2Alist&plex2Alist): 回退部分 encodeURI

2.refactor(emby2Alist&plex2Alist): 耗时打印添加关键字

#### 2024-12-07

1.feat(emby2Alist&plex2Alist): 新增 redirectConfig 参数

2.fix(emby2Alist&plex2Alist): 统一 encodeURIComponent

3.fix(emby2Alist&plex2Alist): 区分远程链接的解码范围

#### 2024-11-27

1.refactor(emby2Alist&plex2Alist): 优化日志打印开始行,以区分原始 error.log 内容和 njs 日志分隔

2.feat(plex2Alist): 解决上游服务双重响应头问题,plex 自身内部不规范,与此脚本无关

#### 2024-11-26

1.feat(emby2Alist&plex2Alist): fallbackUseOriginal

#### 2024-11-24

1.refactor(emby2Alist&plex2Alist): 优化 strMatches 的日志打印量

#### 2024-11-21

1.fix(emby2Alist&plex2Alist): 增强 addAlistSign 特定情况覆盖

#### 2024-11-20

1.feat(emby2Alist&plex2Alist): alistRawUrlMapping

2.fix(emby2Alist&plex2Alist): 修复 blockDownload 实现,支持屏蔽 Infuse 下载

#### 2024-11-17

1.强制 Infuse 支持 strm 播放,当然这是实验性质的,因为修改了文件名后缀,绕过了白名单检测,
理论上任何程序都应该是实时取二进制文件头/魔术头判断文件类型,实测播放器应该都是这样工作的,
假如是使用 FFmpeg 的话,都是可以播放成功的

1.1 加上很久之前修改了 strm 的在 plex 的 Media/Part 对象的 container 字段填充了一个默认值 mp4 进行欺骗支持,
以上不区分客户端都进行了修改,此次仅针对 Infuse 客户端,强制修改了 Part 对象的 file 字段/文件地址,添加了 .mp4 后缀进行欺骗支持,
所以在媒体详情或日志或报文中发现 strm 的这两个字段信息有误的话,是预期修改结果,请无视

1.2 对比没有修改这两个字段进行欺骗的情况下,原本 plex 对于 strm 播放的支持不够完善,具体为
Web 端和官方 plex 客户端响应了 307 重定向(和 302 差不多意思),但是重定向地址为了安全考虑强制加了服务器的域名前缀,导致无法正常播放,
而响应给第三方播放器的重定向地址是正确的,理论上除 Infuse 外,其他第三方播放原生支持 strm 播放,不需要此反代修改

1.3 没欺骗 Infuse 前,这边简单测试 HamHub: 1.3.9(267) 是正常播放 strm 的,欺骗后 Infuse-Direct/8.0.3 也是支持了,
具体测试媒体为 mkv 1080p HEVC,文件名为 xxx.strm,只针对 Infuse 返回的 Part 对象的 file 字段/文件地址为,
xxx.strm.mp4, Infuse 中媒体的内封字幕也是兼容的可以切换

1.4 唯一缺点是开始播放会比较慢,大概 5-8 秒,这个没办法,plex 相对 emby 没有客户端首次播放 strm 后上报补充媒体信息的功能

1.5 另外测试发现 Infuse 对于 emby 是没有屏蔽 strm 文件的详情页的,只对 plex 禁用了,原因未知

#### 2024-11-11

1.115 最近风控比较严格, alist 驱动上前端能填写的最小值 1 已经无法匹配远端限流熔断策略,
根据 alist issues 与 PR 得知网页描述单位错误,目前需要设置为 0.5 速率才能满足需求,
即流速为 2 秒 1 个请求,建议尽快更改为小数避免风控损失

2.【限制所有 api 请求速率(1r/[limit_rate]s)】目前正确为 ([limit_rate]r/1s), 0.1 意味 10 秒 1 个请求

3.更改为小数的方法,停止 alist => 下载 data.db 数据库文件 
=> 使用 [navicat-premium-lite](https://www.navicat.com.cn/products#navicat-premium-lite) 数据库管理工具免费版打开
=> navicat 中双击打开 data.db 的 main 数据库 => 表 => 右侧 x_storages 双击
=> 通过 drive 字段将鼠标点击到 115 Cloud 上 => 点击右下角倒数第二行的表单视图
=> addition 字段 => json 字段的 "limit_rate" 属性并修改 : 后的数值
=> ctrl + s 保存/点击左下角的对勾应用更改 => 关闭 data.db 连接
=> 更名原始的 data.db 为 data.db.bak 进行备份
=> 将修改后的 data.db 传输到服务端 => 重新启动 alist 即可

#### 2024-11-02

1.精确带参数的 strm 路径截取解码

#### 2024-10-29

1.修复带参数的 strm 路径截取编码

#### 2024-10-22

1.测试最新的稳定版 nginx:1.27.2 发行版,内置的 njs:0.8.6 可能存在内存泄漏问题,导致启动时内存从之前的占用 30MB 暴增至 333MB,
且 nginx -s reload 时新开的 worker 线程导致总占用内存占用进一步暴涨到 1GB,导致重载命令卡死和系统内存耗尽机器卡死

2.目前固定版本为 nginx:1.27.1 待 nginx 官方修复后再改回 nginx:latest 镜像,
为防止意外内存泄漏卡死机器,docker 脚本已添加资源限制,默认 memory: 128M 也可 memory: 256M

#### 2024-10-13

1.修复变量未初始化的日志输出,此问题不影响任何功能
https://github.com/nginx/njs/issues/668

#### 2024-08-29

1.修复 mediaPathMapping 中的 r 上下文变量传递

#### 2024-08-28

1.移除错误的 proxy_buffering off; 设置,对于大文件只会降低磁盘临时文件的占用,但会增加磁盘IO,进而导致 CPU 占用率增加

#### 2024-08-22

1.plex 路由规则添加了 r.XMedia 对象,以支持码率/媒体时长/媒体大小...之类的判断,特别需要注意原始数值的单位和 emby 不同

#### 2024-08-14

1.升级全体匹配表达式的匹配符类型以增加数值比较

#### 2024-08-04

1.为 mediaPathMapping 添加生效分组规则,需要注意假如规则中有 UserId 或 X-Emby-Device-Id 之类缩小了范围的,
此时 routeCacheConfig.keyExpression 路由缓存表达式也需酌情缩小范围,区别为直链缓存范围大命中率高,默认仅按媒体版本区分,
不缩小范围会导致头一个设备访问添加了直链缓存后,后续该相同版本的媒体将跳过 mediaPathMapping 处理直接返回缓存的直链

#### 2024-07-25

1.修复 ngx.fetch API 没传递 Host 头导致的端口丢失

#### 2024-07-18

1.修复 routeRule 分组规则的错误判断

#### 2024-07-15

1.clientSelfAlistRule 添加分组,修复 redirectStrmLastLinkRule 分组

2.升级 util.strMatches 以支持字符串形式指定取反操作,不影响历史的数字类型参数,但后续建议使用字符串形式以增强可读性

#### 2024-07-14

1.redirectStrmLastLinkRule 添加分组

#### 2024-07-09

1.去除 mediaMountPath empty 情况的默认走源服务中转,具有二义性,无法区分是未填写还是需要 mediaPathMapping 手动处理,
可选优化方向为对比路径映射前后的是否相同,来进一步区分,但仍旧存在未知性,可能不符合实际情况,
故回退到之前的需要 routeRule 路由规则手动指定比较稳妥

#### 2024-06-01

1.修复 L2 缓存只存不取 bug

#### 2024-05-30

1.同步 emby 代码实现 plex 的 L2 缓存功能

#### 2024-05-26

1.完善 plexApiHandler 的责任链模式,方便后续扩展

#### 2024-05-21

1.拆分配置文件,根据自身倾向选择 exampleConfig 中的配置并参照注释

#### 2024-05-19

1.提供获取软连接真实路径的配置项,前提条件是此程序或容器必须挂载或具有对应目录的读取权限,否则将跳过处理,不生效,
只做了简单的测试,可能暂时存在和非本地文件路径走代理判断稍微有些冲突,自行尝试配置 mediaMountPath 或 routeRule

#### 2024-05-11

1.修复错误的 proxy_buffering off 层级导致的缓存失效

#### 2024-05-10

1.放开 plex 的原始转码功能,这里只是不做修改,交给原始服务中转处理,具体是否转码由 plex 客户端自己判断上报的,
且 web 端八成都会上报为转码,多半是只支持 AAC 的音频,FLAC 和 DTS 均会转码,
~~侧重直链成功率的不建议开启此选项~~,
侧重播放成功率的可以开启,
~~因 plex 比较封闭,目前客户端自身上报为转码,可能没办法切换回直链,~~
需要自己尝试调节客户端网络质量,经热心网友协助测试,客户端可以在播放设置 -> 质量 -> 原始质量,来手动切换回直链,
目前 plex 对比 emby 的默认播放形式暂时存在不一致情况, plex 默认为直链, emby 客户端会自行记忆全局的上次播放质量,
不打算更改各客户端的行为,以官方客户端行为为准

#### 2024-05-05

1.还原 115 的链接判断为二级域名,三级域名为 CDN 负载均衡会动态变化,
最好也不要用 alist get 接口中的 provider 字段,使用了 alias 情况下,provider 为 alias 而非 115 Cloud

2.拆分 conf 配置,http 和 https 不要共用相同端口,恢复 plex 默认为 http 配置,IOS 客户端依赖 https,自行配置端口和证书

#### 2024-04-27

1.升级路由缓存配置,缓存的key值可自定义表达式

#### 2024-04-21

1.还原以兼容115部分客户端拖动进度条bug

#### 2024-04-20

1.升级禁用直链规则为路由规则,内部判断变得十分复杂,有一些历史遗留和可能存在一些优先级问题,请自行测试

#### 2024-04-19

1.升级分组禁用直链规则,添加NJS事件日志,重构拆分转码方法

2.经热心网友协助测试,发现拖动进度条黑屏属于emby的ios官方客户端和infuse播放115独有的问题,阿里云盘不存在此问题,
故升级了直链禁用规则,复现测试可以将115直链放到IDM等多线程下载器中,注意设置为获取直链时的UA,即使是115年费会员,
超过2个线程加载,就会导致整个下载进度卡住,时断时续,猜测这两个客户端默认使用了并发分块加载,
如果有相关设置的话(一般没有,是播放器内核自己的行为),自行设置为1,或者放开禁用直链规则

3.115还有一个问题,很久之前做文件迁移时发现的,一个账号不论多少客户端总共的下载进程最大10个,且有日传输量限制,
这个具体多少流量不清楚,复现测试为浏览器开10个任务,官方客户端下载文件夹只算一个任务,就会发现其余客户端无法播放和下载了

#### 2024-04-13

1.注意需要保证njs >= 0.8.0,直接nginx:latest即可,
加入防抖措施,添加内外部重定向地址缓存,以兼容部分客户端不遵循30X重定向规范导致的短时过多重复请求穿透到alist,
例如emby安卓客户端,infuse,表现形式为每次拖动进度条都会重复请求emby原始串流地址,忽略上次拿到的重定向后地址,
Web端没有此问题,但是播放nas本地视频也会多次请求,故强制兼容解决,
默认按阿里云盘的直链最大有效时间15分钟,请勿随意更改此时间

#### 2024-04-12

1.添加定时任务默认7天自动清空nginx日志,请结合日志重要程度和硬盘占用情况自行调整为合适间隔,建议不要改为小于1天以免影响性能,
使用条件为没有更改过默认日志的路径和名称,且需要更新最新版本njs
```
/var/log/nginx/error.log
/var/log/nginx/access.log
```

2.添加限流配置示例,只对302之前的请求生效,302后是直连第三方服务器,无法进行控制

#### 2024-04-11

1.添加nginx对接日志中心示例配置,可以和原xxx_log共存,如有需要,打开注释并修改为自己的ip和端口即可
发送日志到syslog,默认使用UDP的514端口,群晖=>日志中心=>接收日志=>新增=>名称随意,保持默认的BSD格式,UDP,514

#### 2024-04-08

1.增强禁用直链的规则配置,docker环境需要注意此参数客户端地址($remote_addr),nginx容器网络必须为host模式,不然此变量全部为内网ip,判断无效

#### 2024-04-05

如何避免媒体服务器频繁进行整库扫描刮削,导致内存占用飙升且影响性能,并范围太大会触发网盘的熔断机制

1.部分网盘熔断恢复周期,期间会全部拒绝服务,阿里云盘大概为30分钟到1小时,115网盘则为1-2小时

2.简单方案,发现整库扫描情况立即重启媒体服务,会消停几小时,但治标不治本,之后还会继续重试,控制台和计划任务里不会显示,无法强制停止

3.alist一定要开启115网盘驱动的限制速率,它的限制比较严格,一扫库必定熔断,默认为2【限制所有 api 请求速率(1r/[limit_rate]s)】,
意味着 QPS **速率** 为 2 ,即 1 秒处理 2 个请求,忽略(1r/[limit_rate]s)这个描述,是错误的,
~~意味着2秒内只处理1个请求,个人设置为1也是没问题的,此为最小值~~,为0是没限制,缺点是整库扫持续时间会达到一周,但是不会触发熔断,比较安全,
阿里网盘的熔断机制相对宽松很多,除非一次性文件太多,但是截止当前,alist并没有当前网盘的限流参数

4.最简单,全部使用strm文件解决,没有播放的情况下默认不会进行刮削,emby对此兼容性较好,只在第一次播放后会将媒体流参数信息存入数据库,
下次播放将跳过分析过程,表现形式为秒播,pelx对此无法跳过分析过程,播放开始会长达6-8秒等待,以上为官方客户端,第三方客户端不会有分析过程

以下为猜想未经测试,仅供记录

1.限流可以放在nginx反代配置,流量路径为 nginx-媒体服务 => 媒体服务 => cd2/rclone => nginx-alist => alist

2.媒体库触发强制自动扫库的根本原因为媒体文件的最后修改时间 > 入库时的最后修改时间,有条件可以在nginx-alist这层做反代返回假的最后修改时间,
或者等待alist添加自定义配置最后修改时间功能,截止目前,并没有相关issue

3.从挂载层解决,查询rclone官方文档得知有缓存参数,此测试结果为会在自定义配置的缓存目录同目录结构下,优先生成一个缓存文件,
缓存文件属性显示大小等于原始文件,但是实际占用大小只为读取的文件大小,例如1G文件,被刮削视频头后,大概实际只占用40%,完全没读取过,只占用0KB,
但是此缓存文件最后修改时间为最后一次读写时间,文档中没有自定义配置的参数,如果想要Web控制台,可以再套一层cd2

#### 2024-04-04

strm的plex官方客户端播放,因为它自身没有刮削stream信息,例如视频流、音频流解码器,所以播放时存在一个分析过程,
浏览器控制台可以看到分析过程和结果,根据网速决定,至少也要5-8秒,
和emby不同,emby第一次播放后就会将分析后的媒体信息存入数据库,详情页下方可以看到,所以第二次播放后就是秒播放

...过度想象了,局域网环境直接用ip:nginx端口就行了,不会经过xxx.plex.direct:32400,这是plex对于域名https的局域网兼容

vpn局域网模拟测试了下,无解,plex这点强制性太高,在服务启动时候时候就会把局域网和公网ip还有自定义服务器访问 URL上传到plex.tv,
同时也上传了geoip服务器的地理位置信息。。。(这个查询说明,默认只有管理员可以看到此信息,不用过度担心)

全局刷新页面可以看到 https://clients.plex.tv/api/v2/resources
这个接口调用,局域网的优先级是最高的,只要联通,详情页就不会请求当前访问的域名或ip了,本来我的环境是docker plex host网络,宿主机局域网段是192.168.xxx, 改为了bridge网络,甚至映射了32400到22400, 结果还是发现plex自己请求172.xxx的docker桥接网段且用了22400,因为群晖的docker有些残废,无法测试container网络模式。

plex部分接口优先使用局域网,本意是好的,提升网络反应和增加服务容错,它本身貌似没有提供相关参数关闭这个行为,本来我以为的关闭本地网络发现和关闭中转可以禁用此行为,但是局域网下并没有生效,只能自行寻找偏方强行禁用了。
以下是猜测,任选一个应该可以解决,但是没有实际测试过

服务端方向

1.较难,想办法将plex服务和其他局域网设备严格网络隔离,局域网找不到就会走自定义url了,隔离方式可以试试docker的container指定nginx的容器名称,或者添加防火墙规则,限制只有nginx可以访问plex

2.很难,基本无法阻止,尝试阻止plex上传局域网ip或者改写报文内容将
https://clients.plex.tv/api/v2/resources
~~以达到将自己域名connections.local = true,~~
这是客户端的查询接口,需要自己扒服务端plex与plex.tv上报的接口

客户端方向

1.较简单,使用路由器的访客wifi内网隔离功能,或者连接旁路由的wifi,以达到隔离plex局域网访问

2.较简单,使用代理软件的不同路由模式尝试,或者更改客户机的防火墙规则禁止掉plex的局域网访问

3.较简单,plex安卓官方客户端高级设置里可以自定义连接ip和端口,可以留空ip只填nginx的短裤,注意ios没有这个选项

4.很简单,使用公网访问自己plex,避免局域网的使用情况,确保nginx的处理生效

5.最简单,ios平台使用第三方客户端,原本plex对于strm的支持就是只能远程直链的重定向下载,响应的是301,而部分第三方客户端播放可能使用的下载接口,支持情况不统一
可以断定plex就是把这个活丢出去了,自身客户端并不想支持播放,因为还有bug,体验不是很好,如果媒体库全部为远程strm直链,且客户端全部为第三方,其实用不着部署nginx了

测试已通过

1.局域网环境下的Web浏览器添加拓展解决,并更新最新代码
![e6cb4294e72b3140870f42da1bb966bb](https://github.com/bpking1/embyExternalUrl/assets/42368856/96e1a512-2021-4aff-83dc-bc1424d6e0db)
![image](https://github.com/bpking1/embyExternalUrl/assets/42368856/ab71279e-296c-4845-af69-19738b25aae2)

#### 2024-03-30

1.增强路径映射功能,区分来源类型

2.plex的strm两种都属于强行支持,都可能存在播放记录和回传bug,根本在于pelx自身播放没有处理strm的逻辑

3.添加默认可选参数以支持issue建议的指定strm规则获取重定向后的地址进行转发,兼容局域网的strm链接

4.测试发现plex非常容易擅自使用中转域名,即使设置里中转已关闭并且指定了plex发现网络的自定义链接,例如用梯子的时候,虽然选择的绕过局域网和大陆,但是PlexWeb马上会变更使用["https://192-168-31-200.{uuid}.plex.direct:32400/library/metadata/180"]这样的链接导致绕过了nginx的处理

4.1.建议直链不正常的时候关注下当前请求的url,确认api有经过nginx的处理

5.感谢 @sgpublic 提供的 alist sign 计算方案
~~5.alist >= 3.20的默认对直链开启了sign全部参数,属于额外验证,不接受token验证,~~
~~如果要兼容,性能会很差,需要多用token请求一次alist获取到直链和sign参数,解决方案两种~~

~~5.1.用/开头的路径,这样会用alistToken走fsGet接口一次获取最终直链返回,缺点是官方客户端字幕流不正常且播放记录不准确或者没有~~

~~5.2.nginx请求的alist建议关闭设置-全局-签名所有,将此alist部署为和nginx同一局域网,接口响应也会快很多,通常在200ms-2000ms之间,跨网络会更慢~~
~~如果对直链安全有介意,去掉此alist的公网端口映射,只在局域网使用,公网使用另行部署一个开启sign全部的alist~~

#### 2024-03-28

1.添加基本的配置示例文件,若符合需求,更改内容并删除文件名后缀,复制文件到上一级目录覆盖原始文件即可,\emby2Alist\nginx\conf.d\constant.js

#### 2024-03-26

1.强制支持了strm的播放,目前存在的问题为Web端不支持内封字幕显示

#### 2024-03-25

1.修复了plex对strm文件下载的重定向,内部远程链接的plex源服务自身会响应301支持,添加了内部填写相对路径的情况

2.~~目前的情况是plex官方客户端不支持播放~~
Web端可以直链下载,从之前issus的反馈推断第三方客户端播放用的是下载的api,故理论上应该支持直链

3.理论上官方客户端直链下载后应该可以播放,但是没通行证,暂无法测试

#### 2024-03-18

1.优化请求alist的115直链获取逻辑,透传UA,减少一次302过程,以兼容媒体服务器https而alist为http默认被浏览器客户端强制改写导致的错误

2.~~115直链不在需要clientSelfAlistRule参数,~~
但保留处理逻辑,有特殊需要可自定义配置

#### 2024-03-13

1.媒体服务器https后,如果alist没有https,且相同域名情况,http链接会被浏览器默认强制改写为https,导致115的处理的第一次302会失败

2.地址栏左边-此网站权限-不安全的内容-允许,或者浏览器设置-Cookie 和网站权限-不安全的内容-允许

3.~~非浏览器不存在此问题,~~
例如第三方播放器,默认不会阻止,也可将alist套上证书解决此问题

#### 2024-03-10

1.测试并修复本地视频兼容问题,意外发现http2对本地原始链接的视频在部分跨宽带网络阻断有帮助(电信->联通),如有相同情况请开启http2或者http3

#### 2024-03-07

1.测试并添加https相关示例,plex情况特殊,服务端必须设置-网络-自定义服务器访问 URL: [https://自己的域名:自己的端口号],以发布到plex.tv发现服务器,客户端保持默认设置,不用更改高级设置-自定义ip和端口,高级设置-允许非加密连接-永不,如果plex源服务器没有配证书(也不用配),同时不要更改nginx的proxy_pass值,也就是constant.js中的plexHost值,保持[http://]开头
![image](https://github.com/chen3861229/embyExternalUrl/assets/42368856/5efd2df2-33ba-4dc5-9aff-707f25022a9d)
![image-2](https://github.com/chen3861229/embyExternalUrl/assets/42368856/0431fcc9-9c08-4ccb-af88-71614df5b9c1)

2.Web端还会提示部分内容不安全,无视即可,是plex的设计问题,可自行查找xxx.plex.direct:端口号,关键字解决

#### 2024-03-03
1.更换part连接的路径匹配实现,以彻底解决精度问题,同时将挂载路径缓存至客户端,使用到了xml包,此版本需要njs>=0.7.10

#### 2024-02-29

1.修复剧集页面无法打开的bug

#### 2024-01-19

1.提高web的直链下载匹配精度,使用的nginx的新特性共享变量,缓存了/library/metadata接口中part链接数据,此版本需要njs>=0.8.0,直接nginx:latest即可

~~2.目前的限制是第三方客户端注意必须进一次详情页,再点播放,不要直接点封面图上的播放按钮,下载和第三方客户端不进详情页播放特殊处理的,链接类似/library/parts/81327/1708863299/file.mp4,这个plex没提供直接的api查询出挂载路径,所以这边的处理是用进详情页的数据在nginx共享变量中缓存的,如果缓存没查到,就会用文件名调用plex的接口查询,和首页的查询接口同一个,所以对文件名带-的这种查询不出来,因为plex入库的时候会去掉-~~

#### 2024-01-10

1.兼容新版alist默认签名所有115直链

#### 2024-01-09

~~1.为解决part链接无法获取挂载路径问题,加入偏移量计算,需要大致估算多版本视频的套数,用于计算metadata和part(media)的自增id偏差数~~

#### 2023-11-04

1.参考博客(https://blog.738888.xyz/posts/plex_to_alist_directlink)中的plex直链功能并参考之前的njs实现,
~~实验性(bug)性质支持了直链播放,~~
因为只找到社区维护的简易API(https://plex-docs.vercel.app),
~~所以实现方式比较别扭,目前存在多版本视频不能直链下载的bug。~~

~~2.Plex要直链播放只需要设置远程访问-手动设置公开端口为nginx监听端口,避免客户端优先直连32400,如果路由器做了32400端口转发,不影响外部访问。~~

2.Plex要直链播放需要避免客户端优先直连 32400,
~~去掉路由器的 32400 端口转发~~,
添加 nginx 的端口转发即可
![image](https://github.com/bpking1/embyExternalUrl/assets/42368856/9abc036a-72db-4434-9be7-1f31c2686bb2)
