From 1d73374fff9ce7461ede6b985dd99cc4e9242288 Mon Sep 17 00:00:00 2001 From: truewhile <62226914+truewhile@users.noreply.github.com> Date: Mon, 28 Sep 2026 22:29:36 +0800 Subject: [PATCH] =?UTF-8?q?fix(emby):=20=E7=BD=91=E7=9B=98=E7=9B=B4?= =?UTF-8?q?=E9=93=BE=E7=BB=91=E5=AE=9A=20UA=EF=BC=8C=E7=AC=AC=E4=B8=89?= =?UTF-8?q?=E6=96=B9=E6=92=AD=E6=94=BE=E5=99=A8=E4=BF=9D=E7=95=99=E5=90=8C?= =?UTF-8?q?=E6=BA=90=E4=B8=80=E8=B7=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 115 直链与换取时的 User-Agent 逐字符绑定,换错一律 403。服务端换链用的是邮件客户端 API 层的 UA,而真正拉流的是播放器组件,RodelPlayer 2.2610 两层 UA 不一致(API 层带系统后缀)后会拿到 403 直链,表现为播放失败。非浏览器客户端改为 302 到同源 strm 端点,由播放器自己换链;浏览器仍走服务端换链一跳。 --- internal/handler/emby_playback.go | 25 ++++ .../handler/emby_video_stream_resolve_test.go | 138 ++++++++++++++++++ .../service/stream_direct_redirect_test.go | 37 +++++ internal/service/stream_file.go | 35 +++++ 4 files changed, 235 insertions(+) create mode 100644 internal/handler/emby_video_stream_resolve_test.go diff --git a/internal/handler/emby_playback.go b/internal/handler/emby_playback.go index 0450f7a..b49446b 100644 --- a/internal/handler/emby_playback.go +++ b/internal/handler/emby_playback.go @@ -348,6 +348,12 @@ func embyVideoStreamHandler(svc *service.Container, cloudMode string) gin.Handle // 此前这里把所有错误一律吞成 404:云盘 Cookie 过期、直链解析失败、 // STRM 播放被关闭……在第三方播放器上全部表现为「404 不存在」, // 无法排查。现在区分:行不存在→404;云盘播放不可用/上游故障→502+原因。 + // + // 网盘直链与换取时的 UA 严格绑定,而 Emby 客户端的 API 层与播放器层 UA + // 不保证相同(浏览器一定相同),所以只有浏览器客户端允许服务端短路换链。 + if !isBrowserLikeUserAgent(c.GetHeader("User-Agent")) { + c.Request = c.Request.WithContext(service.WithClientSideSTRMResolve(c.Request.Context())) + } err = svc.Stream.ServeFileWithCloudMode(c.Writer, c.Request, c.Param("id"), cloudMode) switch { case err == nil: @@ -387,6 +393,25 @@ func embyPlaybackRedirectToken(c *gin.Context, svc *service.Container) string { return token } +// isBrowserLikeUserAgent 判断请求是否来自浏览器(含 WebView / Electron 客户端)。 +// +// 只有浏览器能保证「API 请求」与「