use direct stream for resume
This commit is contained in:
@@ -622,6 +622,15 @@ export function useSimilarItems(itemId?: string, limit = 12) {
|
|||||||
* has to load first so the first PlaybackInfo request includes the
|
* has to load first so the first PlaybackInfo request includes the
|
||||||
* saved StartTimeTicks - otherwise the video streams from 0 and
|
* saved StartTimeTicks - otherwise the video streams from 0 and
|
||||||
* reloads mid-playback when the second query returns.
|
* reloads mid-playback when the second query returns.
|
||||||
|
*
|
||||||
|
* `requireDirectStream` is used for resume: the direct-play
|
||||||
|
* /Videos/{id}/stream endpoint with `static=true` returns the file
|
||||||
|
* from byte 0 even when StartTimeTicks is passed, because Chromium
|
||||||
|
* / WebView2 don't send a Range header for the initial GET. The
|
||||||
|
* direct-stream path has the server read the file from the start
|
||||||
|
* position itself and stream the bytes, so the response naturally
|
||||||
|
* starts at the saved offset. Direct-stream is not transcoding -
|
||||||
|
* it's just server-side file I/O with no encoding work.
|
||||||
*/
|
*/
|
||||||
export function usePlaybackInfo(
|
export function usePlaybackInfo(
|
||||||
itemId?: string,
|
itemId?: string,
|
||||||
@@ -629,6 +638,7 @@ export function usePlaybackInfo(
|
|||||||
audioStreamIndex?: number,
|
audioStreamIndex?: number,
|
||||||
maxStreamingBitrate?: number,
|
maxStreamingBitrate?: number,
|
||||||
enabled: boolean = true,
|
enabled: boolean = true,
|
||||||
|
requireDirectStream: boolean = false,
|
||||||
) {
|
) {
|
||||||
const api = useApi()
|
const api = useApi()
|
||||||
const audioPassthrough = usePreferencesStore(s => s.audioPassthrough)
|
const audioPassthrough = usePreferencesStore(s => s.audioPassthrough)
|
||||||
@@ -640,6 +650,7 @@ export function usePlaybackInfo(
|
|||||||
startTimeTicks,
|
startTimeTicks,
|
||||||
audioStreamIndex,
|
audioStreamIndex,
|
||||||
maxStreamingBitrate,
|
maxStreamingBitrate,
|
||||||
|
requireDirectStream,
|
||||||
],
|
],
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
if (!api || !itemId) return null
|
if (!api || !itemId) return null
|
||||||
@@ -657,7 +668,12 @@ export function usePlaybackInfo(
|
|||||||
AudioStreamIndex: audioStreamIndex,
|
AudioStreamIndex: audioStreamIndex,
|
||||||
DeviceProfile: await browserDeviceProfile(audioPassthrough) as any,
|
DeviceProfile: await browserDeviceProfile(audioPassthrough) as any,
|
||||||
AutoOpenLiveStream: true,
|
AutoOpenLiveStream: true,
|
||||||
EnableDirectPlay: true,
|
// For resume, prefer direct-stream so the server starts the
|
||||||
|
// read at StartTimeTicks. Direct-play can't honour start
|
||||||
|
// time on the initial GET. Otherwise let the server pick
|
||||||
|
// direct-play for the no-resume case so the browser plays
|
||||||
|
// the file as-is.
|
||||||
|
EnableDirectPlay: !requireDirectStream,
|
||||||
EnableDirectStream: true,
|
EnableDirectStream: true,
|
||||||
EnableTranscoding: true,
|
EnableTranscoding: true,
|
||||||
AllowVideoStreamCopy: true,
|
AllowVideoStreamCopy: true,
|
||||||
|
|||||||
@@ -331,6 +331,7 @@ export default function PlayerPage() {
|
|||||||
streamAudioIndex ?? undefined,
|
streamAudioIndex ?? undefined,
|
||||||
maxBitrate,
|
maxBitrate,
|
||||||
playbackInfoReady,
|
playbackInfoReady,
|
||||||
|
startTimeTicks !== undefined,
|
||||||
)
|
)
|
||||||
const resolvedSource = playbackInfo?.MediaSources?.[0]
|
const resolvedSource = playbackInfo?.MediaSources?.[0]
|
||||||
const streamUrl = (() => {
|
const streamUrl = (() => {
|
||||||
|
|||||||
Reference in New Issue
Block a user