mirror of
https://github.com/truewhile/MeBox.git
synced 2026-09-28 11:16:37 +08:00
feat(playback): client direct-play decode mode (release host transcoding)
Add an admin toggle playback.direct_only that offloads all decoding to the client. When enabled: - Emby PlaybackInfo no longer advertises SupportsTranscoding nor a TranscodingUrl, forcing Emby/Infuse/Yamby clients to direct play. - HLS endpoints refuse (ErrTranscodeDisabled) so the host never spawns ffmpeg. - Web player forces direct play, hides the HLS toggle, and surfaces a hint. Exposed via /system/info (direct_play_only) and the Settings page. Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
@@ -36,6 +36,11 @@ import (
|
||||
// 该 id 后会把所有派生数据(cookie/收藏/历史)和它绑定。
|
||||
const embyServerID = "mediastation-go-001"
|
||||
|
||||
// PlaybackDirectOnlySettingKey 控制「客户端直连解码」模式:开启后宿主机
|
||||
// 不再提供转码,所有播放交给第三方客户端本地解码(direct play / 302 直链),
|
||||
// 以释放宿主机 CPU 资源。
|
||||
const PlaybackDirectOnlySettingKey = "playback.direct_only"
|
||||
|
||||
// EmbyService produces Emby-shaped JSON.
|
||||
type EmbyService struct {
|
||||
cfg *config.Config
|
||||
@@ -644,7 +649,7 @@ func (e *EmbyService) itemPayload(m *model.Media, fav bool, posMs int64) map[str
|
||||
"Played": played,
|
||||
"PlayedPercentage": pct,
|
||||
},
|
||||
"MediaSources": []map[string]any{e.mediaSource(m, true)},
|
||||
"MediaSources": []map[string]any{e.mediaSource(m, true, false)},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1149,11 +1154,24 @@ func (e *EmbyService) PlaybackInfo(ctx context.Context, mediaID, userID string)
|
||||
return nil, err
|
||||
}
|
||||
return map[string]any{
|
||||
"MediaSources": []map[string]any{e.mediaSource(m, false)},
|
||||
"MediaSources": []map[string]any{e.mediaSource(m, false, e.directPlayOnly(ctx))},
|
||||
"PlaySessionId": fmt.Sprintf("%s-%d", m.ID, time.Now().Unix()),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// directPlayOnly reports whether the admin enabled「客户端直连解码」mode.
|
||||
// In that mode the host never transcodes; clients must direct-play.
|
||||
func (e *EmbyService) directPlayOnly(ctx context.Context) bool {
|
||||
if e.repo == nil || e.repo.Setting == nil {
|
||||
return false
|
||||
}
|
||||
v, err := e.repo.Setting.Get(ctx, PlaybackDirectOnlySettingKey)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return parseBoolSetting(v, false)
|
||||
}
|
||||
|
||||
func (e *EmbyService) playableMedia(ctx context.Context, id, userID string) (*model.Media, error) {
|
||||
if season, ok, err := e.findSeasonGroup(ctx, id, userID); err != nil {
|
||||
return nil, err
|
||||
@@ -1180,7 +1198,7 @@ func (e *EmbyService) playableMedia(ctx context.Context, id, userID string) (*mo
|
||||
// asEmbedded=true:嵌在 /Items 列表里,不包含完整 stream URL(避免暴露
|
||||
// 直链给搜索接口)。/PlaybackInfo 走 false 路径,URL 指向 Emby 兼容
|
||||
// /Videos/{id}/stream(客户端会继续携带 X-Emby-Token 或 append api_key)。
|
||||
func (e *EmbyService) mediaSource(m *model.Media, asEmbedded bool) map[string]any {
|
||||
func (e *EmbyService) mediaSource(m *model.Media, asEmbedded, directOnly bool) map[string]any {
|
||||
src := map[string]any{
|
||||
"Id": m.ID,
|
||||
"Name": m.Title,
|
||||
@@ -1190,7 +1208,7 @@ func (e *EmbyService) mediaSource(m *model.Media, asEmbedded bool) map[string]an
|
||||
"Protocol": "Http",
|
||||
"Type": "Default",
|
||||
"IsRemote": false,
|
||||
"SupportsTranscoding": true,
|
||||
"SupportsTranscoding": !directOnly,
|
||||
"SupportsDirectStream": true,
|
||||
"SupportsDirectPlay": true,
|
||||
"SupportsProbing": true,
|
||||
@@ -1199,7 +1217,11 @@ func (e *EmbyService) mediaSource(m *model.Media, asEmbedded bool) map[string]an
|
||||
}
|
||||
if !asEmbedded {
|
||||
src["DirectStreamUrl"] = "/Videos/" + m.ID + "/stream"
|
||||
src["TranscodingUrl"] = "/Videos/" + m.ID + "/stream"
|
||||
// 直连解码模式下不下发 TranscodingUrl,迫使客户端本地解码直连,
|
||||
// 宿主机不参与转码。
|
||||
if !directOnly {
|
||||
src["TranscodingUrl"] = "/Videos/" + m.ID + "/stream"
|
||||
}
|
||||
}
|
||||
if strings.TrimSpace(m.STRMURL) != "" {
|
||||
// STRM 重定向:客户端直接拉远端,跳过我们这一层。
|
||||
|
||||
Reference in New Issue
Block a user