From d14f15a2f8537da2b8dbb8d19d3a69b440e2c122 Mon Sep 17 00:00:00 2001 From: mani Date: Wed, 25 Feb 2026 21:36:59 +0100 Subject: [PATCH] Fix CRT shader: pass streamOptions via PlaybackInfo body, not URL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous approach of appending streamOptions[crtShader]=true to the transcoding URL didn't work — the server only reads StreamOptions from the PlaybackInfo request body (PlaybackInfoDto), not from the streaming endpoint URL query string. Pass streamOptions as part of the getPlaybackInfo query so the server embeds them in the TranscodingUrl. Also propagate crtShadowMask the same way. Remove the broken URL-appending code. Co-Authored-By: Claude Sonnet 4.6 --- src/components/playback/playbackmanager.js | 26 ++++++++++++---------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/components/playback/playbackmanager.js b/src/components/playback/playbackmanager.js index bb1a5e31d2..7d923516d4 100644 --- a/src/components/playback/playbackmanager.js +++ b/src/components/playback/playbackmanager.js @@ -470,6 +470,9 @@ async function getPlaybackInfo(player, apiClient, item, deviceProfile, mediaSour if (options.allowAudioStreamCopy != null) { query.AllowAudioStreamCopy = options.allowAudioStreamCopy; } + if (options.streamOptions) { + query.StreamOptions = options.streamOptions; + } if (mediaSourceId) { query.MediaSourceId = mediaSourceId; } @@ -1747,6 +1750,14 @@ export class PlaybackManager { const currentPlayOptions = currentItem.playOptions || getDefaultPlayOptions(); + const crtStreamOptions = (function () { + const pd = getPlayerData(player); + if (!pd.enableCrtShader) return undefined; + const opts = { crtShader: 'true' }; + if (pd.crtShadowMask != null) opts.crtShadowMask = String(pd.crtShadowMask); + return opts; + })(); + const options = { maxBitrate, startPosition: ticks, @@ -1756,7 +1767,8 @@ export class PlaybackManager { enableDirectPlay: params.EnableDirectPlay, enableDirectStream: params.EnableDirectStream, allowVideoStreamCopy: params.AllowVideoStreamCopy, - allowAudioStreamCopy: params.AllowAudioStreamCopy + allowAudioStreamCopy: params.AllowAudioStreamCopy, + streamOptions: crtStreamOptions }; getPlaybackInfo(player, apiClient, currentItem, deviceProfile, currentMediaSource.Id, liveStreamId, options).then(function (result) { @@ -2878,17 +2890,7 @@ export class PlaybackManager { playMethod = mediaSource.SupportsDirectPlay ? 'DirectPlay' : 'DirectStream'; } else if (mediaSource.SupportsTranscoding) { - let transcodingUrl = mediaSource.TranscodingUrl; - - // Append CRT-Lottes shader option when enabled for this session. - if (getPlayerData(player).enableCrtShader) { - const sep = transcodingUrl.includes('?') ? '&' : '?'; - transcodingUrl += sep + 'streamOptions%5BcrtShader%5D=true'; - const maskVal = getPlayerData(player).crtShadowMask; - if (maskVal !== undefined && maskVal !== null) { - transcodingUrl += '&streamOptions%5BcrtShadowMask%5D=' + maskVal; - } - } + const transcodingUrl = mediaSource.TranscodingUrl; mediaUrl = apiClient.getUrl(transcodingUrl);